Skip to main content

CSS Container Queries: die besseren Media Queries

Jeder Webentwickler kennt Media Queries. Diese sind notwendig, um die verschiedenen Elemente der Webseite auf jedem Gerät schön darzustellen.

Wir zeigen euch ein einfaches Beispiel anhand von Produkt-Teasern. Diese sollen auf mobilen Geräten im Hochformat untereinander, auf Tablet im Hochformat nebeneinander und auf Desktop im Querformat nebeneinander dargestellt werden.

Wir lösen das Problem zuerst wie gehabt mit Media Queries und zeigen deren Grenzen auf. Danach zeigen wir, wie die bestehenden Probleme mit Container Queries gelöst werden können.

Darstellung auf Desktop

Darstellung auf Tablet

Darstellung auf Mobile

Let's get started

HTML:
Der «times»-Helper wiederholt den Code-Block so viele Male, wie angegeben.

<div class="container">
    <div class="row">
        {{#times 2}}
            <div class="product-teaser">
                <div class="product-teaser__image">
                    <img src="https://via.placeholder.com/400x300">
                </div>
                <div class="product-teaser__content">
                    <h3>Produkt Titel</h3>
                    <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt
                        ut labore et dolore magna aliquyam</p>
                </div>
            </div>
        {{/times}}
    </div>
</div>

CSS:


.row {
  display: flex;
  flex-wrap: wrap;
}

.product-teaser {
  padding: 0 5px 10px;
  width: 100%;

  @media (min-width: 768px) {
    width: 50%;
  }

  @media (min-width: 992px) {
    display: flex;

    .product-teaser__image, .product-teaser__content {
      width: 50%;
    }

    .product-teaser__image {
      padding-right: 5px;
    }
  }
}

Anwendung

Nun möchten wir auf einer anderen Seite diese beiden Produkt-Teaser neben einem Bild darstellen.

<div class="container">
    <div class="wrapper">
        <img src="https://via.placeholder.com/400x300">
        <div class="row">
            {{#times 2}}
                <div class="product-teaser">
                    <div class="product-teaser__image">

      <img src="https://via.placeholder.com/400x300">
                    </div>
                    <div class="product-teaser__content">
                        <h3>Produkt Titel</h3>
                        <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt
                            ut labore et dolore magna aliquyam</p>
                    </div>
                </div>
            {{/times}}
        </div>
    </div>
</div>

Würden wir nun einfach in HTML ein Bild neben den beiden Teasern einfügen, so hätten wir das Problem, dass diese auf Desktop im Querformat dargestellt werden. Obwohl das Hochformat besser passen würde.

Eine mögliche Lösung wäre eine neue CSS Regel, welche das Bild vor dem «row»-Element (nachfolgend Teaser-Row genannt) berücksichtigt. Auch könnte man bei den Produkt-Teasern neben dem Bild eine zusätzliche Klasse setzen.

img + .row .product-teaser {
  display: block;
  .product-teaser__image, .product-teaser__content {
    width: 100%;
    padding: 0;
  }
}

Bei diesem Dummy-Beispiel ist dies einfach zu realisieren. Jedoch muss darauf geachtet werden, dass immer ein Bild neben der Teaser-Row eingefügt wird. Man kann also nicht frei wählen, welchen Inhalt man da platziert. Effizienter wäre es doch, wenn wir prüfen könnten, über wie viel Platz die Teaser-Row verfügt. So können wir die passende Ansicht der Produkt-Teaser automatisch bestimmen. Mit den Container Queries wird dies möglich.  

 

Container Queries schaffen hier Abhilfe

Wir haben nun einmal zwei Produkt-Teaser neben einem Bild und einmal zwei Produkt-Teaser auf einer Zeile:

<div class="container">
    <div class="wrapper">
        <img src="https://via.placeholder.com/400x300">
        <div class="row">
            {{#times 2}}
                <div class="product-teaser">
                    <div class="product-teaser__image">
                        <img src="https://via.placeholder.com/400x300">
                    </div>
                    <div class="product-teaser__content">
                        <h3>Produkt Titel</h3>
                        <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
                            invidunt
                            ut labore et dolore magna aliquyam</p>
                    </div>
                </div>
            {{/times}}
        </div>
    </div>

    <div class="row">
        {{#times 2}}
            <div class="product-teaser">
                <div class="product-teaser__image">
                    <img src="https://via.placeholder.com/400x300">
                </div>
                <div class="product-teaser__content">
                    <h3>Produkt Titel</h3>
                    <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
                        invidunt
                        ut labore et dolore magna aliquyam</p>
                </div>
            </div>
        {{/times}}
    </div>
</div>

CSS:


.row {
  display: flex;
  flex-wrap: wrap;
  container-type: inline-size;
}

.product-teaser {
  padding: 0 5px 10px;
  width: 100%;

  @media (min-width: 768px) {
    width: 50%;
  }
}

@container (min-width: 1000px) {
  .product-teaser {
    display: flex;

    .product-teaser__image, .product-teaser__content {
      width: 50%;
    }

    .product-teaser__image {
      padding-right: 5px;
    }
  }
}

Neu bei der Row dazugekommen ist:

container-type: inline-size

Die Media Query für Desktop wurde durch eine Container Query ersetzt. 

Da der Container neben dem Bild nicht mehr als 1000px breit ist, werden die CSS-Regeln in dieser Query nicht auf diesen Bereich angewandt. Somit können wir die Teaser beliebig platzieren. Sobald genügend Platz vorhanden ist, werden diese im Querformat dargestellt.

Standardmässig geht die Container Query immer auf die Breite des Parent-Elements. Bei uns wird die Query auf Produkt-Teaser mit einer Teaser-Row als Parent angewandt. Dies kann jedoch mit der

container-name: name;

Property auf dem Container überschrieben werden. Zusätzlich wird der Name bei der Query mitgegeben.

.row {
  container-type: inline-size;
  container-name: teaserRow;
}

@container teaserRow (min-width: 1000px) {
  .product-teaser {
  }
}

Zusätzlich gibt es Container Query Units:

  • cqw (Container Query Width) – 1% der Breite des Containers
  • cqh (Container Query Height) – 1% der Höhe des Containers
  • cqi (Container Query Inline) – 1% der inline Grösse des Containers
  • cqb (Container Query Block) – 1% Der Block Grösse des Containers
  • cqmin (Container Query Minimum) – Der kleinere Wert von cqi oder cqb
  • cqmax (Container Query Maximum) – Der grössere Wert von cqi oder cqb

Beispiel:
Die Titel und Textgrösse wird anhand der Breite des Containers gesetzt:

h3 { 
 font-size: 2cqw;
}

p {
 font-size: 1.5cqw;
}

Fazit

Container Queries sind eine gute Möglichkeit für die Entwicklung von responsiven Webseiten mit dynamischen Elementen, die sich jederzeit dem Bildschirm optimal anpassen. Jedoch werden sie leider noch nicht ganz von allen Browsern unterstützt, was die Verwendung noch nicht ganz so einfach macht.

Die aktuell unterstützten Browser können hier geprüft werden: https://caniuse.com/?search=container%20queries

Geschrieben von:
Thomas Bieli, Frontend-Entwickler bei der raffiniert media AG