Container Queries & Element Queries im Responsive Web Design
Container Queries bzw. Element Queries lösen viele Probleme im Responsive Web Design, die Media Queries nicht lösen können.

Update: Es gibt mittlerweile eine native Syntax namens @container. Details dazu findet ihr hier.
Eine der drei Grundvoraussetzungen, die Ethan Marcotte 2010 in seinem legendären Artikel »Responsive Webdesign« als Grundlage für selbiges aufgeführt hat, sind die Media Queries. Mit Media Queries kann man das Layout einer Website anhand von Geräteeigenschaften verändern. Beispielsweise, wenn der Viewport eine bestimmte Größe über- oder unterschreitet. Seit 2010 ist einige Zeit vergangen und es hat sich in der Praxis herausgestellt, dass für die Veränderung des Layouts die Viewportgröße nicht immer der ideale Ausgangspunkt ist. Häufig wäre es besser, wenn ein Element immer dann verändert werden könnte, wenn der Raum für dieses spezielle Element einen bestimmten Punkt über- oder unterschreitet. Genau das sollen sog. Element Queries bzw. Container Queries erledigen. Und noch vieles mehr.
Der Weg zum modularen Design
Früher haben Webdesigner ein Projekt vorrangig in Unterseiten geplant und gelayoutet. Es wurden z. B. eine Startseite, eine Produktansicht, eine Textseite usw. erstellt. Dann kam ab 2011 das Thema Responsive Design auf und erforderte ein flexibles Layout, dass auf verschiedenen Bildschirmgrößen funktioniert.
Breakpoints für Geräteklassen
Designer ohne HTML- und CSS-Kenntnisse konnten in Photoshop & Co. keine wirklich flexiblen Layouts gestalten. Daher haben Sie zusätzliche Layouts für verschiedene Geräteklassen entworfen. Im Ergebnis hatte man dann beispielsweise das Layout der Startseite auf dem Smartphone, dem Tablet und dem Desktop gestaltet. Bei der Breite dieser verschiedenen Layouts orientierte man sich meist an der Größe typischer Geräte wie dem iPhone oder dem iPad. Das Ergebnis war daher oft ein sog. adaptives Layout mit wenigen globalen Breakpoints.

Auch entstanden zahlreiche Layout-Dateien, die immer wieder die gleichen Bestandteile besaßen. Beispielsweise ist der Header meist auf allen Unterseiten identisch – musste aber doppelt gepflegt werden. Auch wenn Photoshop und Co. sich größte Mühe gaben den veränderten Bedingungen gerecht zu werden, stellte sich der Workflow als zunehmend träge, fehleranfällig und teuer heraus.
Erstellen Sie Übergangspunkte auf Grundlage der Inhalte und niemals auf Grundlage bestimmter Geräte, Produkte oder Marken. (Google Web Fundamentals)
Breakpoints für Komponenten und gestalterische/Inhaltliche Anforderungen
Designer mit HTML und CSS-Kenntnissen begannen parallel damit Layouts direkt im Browser zu gestalten und während der Arbeit permanent die Viewportgröße zu verändern. Unterstützt wurden Sie von immer besseren Entwickler-Tools in den Browsern. »Echte« responsive Layouts mit einem flüssigen Gestaltungsraster waren die Folge. Auch wurden die Breakpoints zunehmend dort gesetzt, wo der Content oder ein bestimmter Teilbereich des Layouts (die Komponente) eine Veränderung brauchte. Die Vorgehensweise dieser Designer führte daher zu einem robusteren und modularen Ergebnis mit deutlich mehr Breakpoints.

Design-Pattern und -Systeme
Die Vorgehensweise Layouts nicht für Geräteklassen zu gestalten, sondern modular zu entwickeln setzte sich durch, und schlaue Leute begannen damit Konzepte für diesen Workflow zu entwickeln.
Bei Atomic Design-Ansatz werden aus kleineren Einheiten größere Komponenten entwickelt, die später zu Layouts zusammengebaut werden. Auch Frameworks wie Bootstrap und Foundation gehen in diese Richtung. Foundation hat beispielsweise mit den Building Blocks eine entsprechende Bibliothek veröffentlicht. Auch im kulturbanause-Blog findet ihr zahlreiche Design-Pattern – beispielsweise für Navigationen.
Ob nun Atomic Design oder andere modulare Ansätze. Der Trend geht eindeutig in die Richtung responsiver Komponenten, die zu immer größeren Modulen kombiniert werden und gemeinsam mit einem flexiblen Gestaltungsraster letztendlich ein ganzes Projekt ergeben.
Media Queries am Limit
Bei einem derart modularen Aufbau passen Media Queries nicht gut ins Konzept. Mit einem Media Query kann man abfragen, ob ein bestimmtes Gerät (z. B. der Bildschirm) eine bestimmte Eigenschaft (z. B. die Viewport-Breite) besitzt und anschließend darauf reagieren. Doch die Viewport-Breite ist oft nicht relevant für eine Komponente die nur in einem Teilbereich des Layouts platziert wird. Wenn man sich mit responsiven Layouts beschäftigt, merkt man schnell, dass Media Queries an ihre Grenzen stoßen.
Das folgende Beispiel zeigt warum. Das Layout beinhaltet eine typische responsive Komponente – die sog. Card, die aus Bildbereich und Inhalt besteht. Wenn die Card wenig Platz zur Verfügung hat, ist sie blau und das Bild soll über dem Inhalt stehen. Wenn mehr Raum verfügbar ist, soll das Bild nach links rutschen und die Card grün umgefärbt werden.

Wenn wir das Projekt technisch mobile First aufbauen, stellt die blaue Card das Standardverhalten dar. Um bei einer Viewportbreite von 500 Pixeln auf die grüne Card umzuschalten, schreiben wir einen Media Query. Leider müssen wir ab 800 Pixeln das Verhalten widerrufen. Daher bietet es sich an, eine sog. »Media Query Range« zu verwenden, die von 500 bis 800 Pixeln die grüne Card erzeugt. Damit springt ab 800 Pixeln wieder das Standardverhalten ein. Doch bei 1000 Pixeln Viewportbreite müssen wir den Code für die grüne Card erneut schreiben. Vereinfacht dargestellt sieht der Code so aus:
.card {
/* blau */
}
@media screen and (min-width: 500px) and (max-width:800px) {
.card {
/* grün */
}
}
@media screen and (min-width: 1000px) {
.card {
/* grün */
}
}
Die Wiederholung der Stile für »grün« könnten wir in diesem Beispiel durch Zusammenfassen der Media Queries zwar noch vermeiden, doch spätestens wenn eine weitere Unterseite mit alternativem Layout hinzukommt, müssen wir eine Sonderregel schreiben.
Folgendes Verhalten ist für zwei weitere Unterseiten gewünscht:

Wie man sieht, soll die Card nun in der Desktopversion blau sein. Doch da wir die Optik des Elements bisher mit einem Media Query anhand der Viewportbreite festlegen, werden die falschen Stile angewandt. Erst einmal erhalten wir folgendes Ergebnis:

Wir müssen folglich für diese beiden Unterseiten die unerwünschten Stile in den größeren Layoutvarianten überschreiben. In diesem Beispiel ab dem Breakpoint bei 800 Pixeln. Das ist weder flexibel noch robust.
@media screen and (min-width: 801px) {
.page-1 .card,
.page-2 .card {
/* blau */
}
}
Praktischer wäre in diesem Fall eine Komponente die eigene Breakpoints besitzen kann – also beispielsweise auf den verfügbaren Raum im Elternelement reagiert. In unserem Beispiel hätte die Komponente »Card« dann zwei Zustände und einen Breakpoint (Live-Beispiel).

Der Code könnte beispielsweise so aussehen:
.card {
/* blau */
}
/* Schreibweise nach github.com/marcj/css-element-queries */
.card[min-width~="500px"] {
/* grün */
}
Oder so:
.card {
/* blau */
}
/* Schreibweise nach github.com/tomhodgins/element-queries-spec */
@element .card and (min-width:500px) {
$this {
/* grün */
}
}
Oder so:
.card {
/* blau */
}
/* Schreibweise nach github.com/ausi/cq-prolyfill */
.card:media(min-width:500px) {
/* grün */
}
Element Queries & Container Queries
Es gibt im Zusammenhang mit dem oben beschriebenen Wunsch nach einer komponentenbasierten Herangehensweise zahlreiche Gruppen und Entwickler die seit geraumer Zeit an Lösungen arbeiten. KEINE davon ist final und es gibt aktuell keine standardisierte Syntax! Es gibt auch unterschiedliche Ansätze wie das gewünschte Element angesprochen werden kann und daraus haben sich verschieden Begrifflichkeiten entwickelt, die teilweise synonym verwendet werden. Ich nutze für die folgenden Beispiele die Syntax und das Wording des Scripts EQCSS, auf das ich später noch detailliert eingehe.
Was sind »Scoped Styles«?
Ein sog. »Scoped Style« begrenzt die Stile auf einen bestimmten Wirkungsbereich.
/* Wenn .sidebar irgendwo im Dokument existiert … */
@element .sidebar {
/* … reduziere die Breite von .content. Wichtig: .content muss kein Kind-Element von .sidebar sein! */
.content {
width: 60%;
}
}
Sog. »Scoped CSS« gab es in anderer Form übrigens schon einmal – der Browser-Support hat allerdings nachgelassen.
Was sind »Responsive Conditions«?
»Responsive Conditions« erweitern einen Scoped Style um eine Bedingung.
/* Wenn .card existiert und breiter als 500px ist … */
@element .card and (min-width:500px) {
/* … ordne .card-header und .card-content nebeneinander an */
.card-header, .card-content {
flex:1;
}
}
Was sind »Element Queries«?
Die Kombination von Scoped Style und Responsive Condition nennt man »Element Query«. Man kann einen Element Query verwenden um andere Elemente zu stylen oder das gleiche Element. Im letzten Code-Beispiel haben wir beispielsweise die Breite der .card
abgefragt und anschließend die enthaltenen Elemente verändert, wenn die .card
mehr als 500 Pixel Platz hat. Wir haben also eine Abfrage für das Container-Element (die .card
) verwendet, um die Kind-Elemente (.card-header
und .card-content
) zu stylen.
Was sind »Container Queries«?
Aus technischer Sicht ist ein Container Query ein Element Query, der dazu benutzt wird enthaltene Elemente zu stylen. Die Abfrage einer Bedingung erfolgt über einen Container – daher der Name. Container Queries passen gut zusammen mit Namenskonventionen wie BEM. Streng betrachtet sind die klassischen Media Queries auch Container Queries, da man das Styling der Website über die Abfrage einer Container-Eigenschaft verändert.
Vom Konzept her sind Container Queries gegenüber Element Queries eingeschränkt, da ein Element Query immer auch ein Container Query sein kann – aber nicht umgekehrt.
Es ist mit einem Container Query beispielsweise nicht möglich ein Element anzusprechen, dass keine Kindelemente besitzt oder besitzen kann. Ein <input>
-Feld grün umzufärben, wenn es mindestens 20 Zeichen enthält, gestaltet sich mit einem Container Query daher schwierig. Ein Element Query würde beispielsweise folgende Syntax mit dem Schlüsselwort $this
nutzen:
/* Wenn <input> mindestens 20 Zeichen enthält … */
@element input and (min-characters:20) {
/* … ändere die Farbe auf grün */
$this {
color:lime;
}
}
EQCSS – Element Query CSS
Wie bereits mehrfach erwähnt, gibt es in CSS noch keine Element Queries, Container Queries oder ähnliches. Es kursieren verschiedene Ideen in diesem Zusammenhang und es existieren einige JavaScript-Bibliotheken die die verschiedenen Ideen mehr oder weniger einsatzfähig machen.
Eine dieser Bibliotheken ist EQCSS. EQCSS ermöglicht Element Queries mit zahlreichen Bedingungen ab dem Internet Explorer 9 und aufwärts. Ein zusätzliches Skript rüstet den Support bis zum IE8 nach. EQCSS ist auf der Website elementqueries.com bzw. containerqueries.com (… ein Beweis für die Uneinigkeit hinsichtlich des Wordings) und in der zugehörigen (nicht offiziellen!) Spezifikation detailliert erklärt.
EQCSS – Funktionsweise
Das JavaScript kann auf der Website heruntergeladen oder über ein CDN bezogen werden. Es reicht aus, dass Skript im Footer zu laden.
<script src="eqcss.js"></script>
Anschließend können Element Queries im CSS-Code verwendet werden. Ob ihr dazu einen <style>
-Abschnitt im selben Dokument verwendet oder ein über <link>
referenziertes Stylesheet ist euch überlassen. Solltet ihr Element Queries strikt vom restlichen CSS-Code trennen wollen, so stehen auch dafür einige Optionen zur Verfügung.
EQCSS – Syntax
Element Queries nach EQCSS-Spezifikation werden wie folgt geschrieben:
@element SELEKTOR and (RESPONSIVE CONDITION) {
SELEKTOR {
EIGENSCHAFT: WERT;
}
}
Wenn also beispielsweise der <header>
blau eingefärbt werden soll, wenn der <body>
eine Höhe von 800 Pixeln hat, genügt folgender Code:
@element body and (min-height:800px) {
header {
background: blue;
}
}
EQCSS – Responsive Conditions
In EQCSS stehen eine Reihe interessanter Bedingungen für die Abfrage zur Verfügung:
min-width
&max-width
min-height
&max-height
min-children
&max-children
min-characters
&max-characters
min-lines
&max-lines
min-scroll-x
,max-scroll-x
,min-scroll-y
&max-scroll-y
orientation
min-aspect-ratio
&max-aspect-ratio
EQCSS – Meta Selectors
Wenn man EQCSS nutzen möchte um das abgefragte Element direkt anzusprechen, kommt das Schlüsselwort $this
ins Spiel. Das folgende Beispiel zeigt den Code, der notwendig ist um den <header>
blau einzufärben, wenn er selbst breiter als 600 Pixel wird.
@element header and (min-width:600px) {
$this {
background: blue;
}
}
Neben $this
existieren auch noch die Meta Selektoren $prev
für das vorherige Element, $next
für das nächste Element, $parent
für das Elternelement (!!), und $root
für das Root-Element.
Da es beim Dollarzeichen zu Konflikten im Zusammenhang mit Sass kommen kann, möchte ich hier auf eine Lösung hinweisen.
EQCSS – CSS Einheiten
Wenn EQCSS im Einsatz ist, können auch neue Einheiten verwendet werden. Die Einheit ew
steht für die Breite des Elements (element width), eh
für die Höhe (element height). emin
und emax
stehen für den jeweils kleineren bzw. größeren Wert – genauso wie bei den verwandten CSS-Einheiten vh
, vw
, vmin
und vmax
.
EQCSS – CSS Funktionen
In EQCSS kann auch eine neue CSS-Funktion namens eval()
verwendet werden. Damit ist es möglich JavaScript einzuschleusen.
EQCSS Beispiel 1 – Mehrspaltige Komponenten
Das folgende Beispiel zeigt einen Hauptinhalt und eine Seitenleiste, die jeweils drei Boxen enthalten.
<main class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
</main>
<aside class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
</aside>
Mit Flexbox wird dafür gesorgt, dass die Seitenleiste neben dem Inhaltsbereich sitzt und dass die Boxen jeweils die volle Höhe des Container-Elements einnehmen.
* { box-sizing: border-box; }
body {
display: flex;
justify-content: space-between;
}
main { width: 70%; }
aside { width: 25%; }
.box {
background: white;
margin:.5em;
padding:1em;
flex:1;
}
.container {
padding:.5em;
height:300px;
background:#8cb11c;
display: flex;
flex-direction: column;
}
Nun sollen die Boxen innerhalb des Containers nebeneinander angezeigt werden, sobald der Container 600 Pixel breit ist. Dafür nutzen wir folgenden Element Query:
@element .container and (min-width: 600px) {
$this {
flex-direction: row;
}
}

EQCSS Beispiel 2 – Formulareingabe
Das folgende Formular besteht aus drei <label>
/<input>
-Kombinationen.
<label for="field-1">Bitte gib mehr als 10 Zeichen ein. </label>
<input type="text" id="field-1">
…
Mit einem Element Query prüfen wir, ob in das <input>
-Feld mindestens 10 Zeichen eingegeben wurden. Wenn das der Fall ist, färben wir das Feld grün ein und fügen den Hinweis »Vielen Dank!« mittels Pseudoelement an das vorausgegangene Element (das <label>
) an.
@element input and (min-characters: 10) {
$this {
background:#8cb11c;
color:white;
}
$prev::after {
content:'Vielen Dank!';
}
}

EQCSS Beispiel 3 – Sticky Navigation
Im nächsten Beispiel sitzt die Navigation unter dem Header. Wenn gescrolled wird, soll die Navigation fixiert werden, sobald ihre Oberkante die Oberkante des Viewports erreicht hat.
/* relevanter CSS Code */
@element body and (min-scroll-y: 600px) {
nav {
position: fixed;
top:0;
left:0;
right:0;
}
}
EQCSS Beispiel 5 – Viewport- und Elementgröße auslesen
Mit Hilfe von JavaScript und der Funktion eval()
ist es möglich die Viewport-Breite oder die Höhe eines Elements auszulesen. Mittels Pseudoelement ::after
wird die Abmessung dann sichtbar gemacht.
<body>
<div class="resizeable"></div>
</body>
@element body {
$this::after {
position:fixed;
top:1em;
left:1em;
content: 'eval("'Viewport: '+window.innerWidth+' x '+window.innerHeight")';
}
}
@element .resizeable {
$this::after {
content: 'eval("'Element: '+offsetWidth+' x '+offsetHeight")';
}
}

Alternative Lösungen
Neben der hier beschrieben Lösung mittels EQCSS gibt es auch alternative Ansätze, die ich euch nicht vorenthalten möchte.
Kritikpunkte
Auch wenn der Ruf nach einer Element/Container Query-Lösung laut ist, so gibt es doch auch Kritik.
Beispielsweise sind in allen mir aktuell bekannten Lösungsansätzen Endlosschleifen möglich. Der folgende Code erzeugt beispielsweise einen solchen Konflikt durch Selbstreferenzierung:
// Wenn der div breiter ist als 1000 Pixel …
@element div and (min-width: 1000px) {
// … verkleinere ihn auf 999 Pixel
$this {
width: 999px;
}
}
Das ist in der Tat ein Problem, aber möglicherweise nicht ein solcher Blocker für die Weiterentwicklung von Element- bzw. Container Queries wie es oft dargestellt wird. Denn erstens ist ein solcher Konflikt auch mit validem Standard-CSS möglich (siehe Beispiel) und zweitens springt der Browser bei einem Element Query-Konflikt nicht permanent zwischen zwei Bedingungen hin und her. Das bedeutet, dass es zwar ggf. nicht so aussieht wie gewünscht, aber es gibt keine Endlos-Schleife die in einem Browser-Absturz oder ähnlichem resultiert. Zuletzt löst der CSS-Befehl contain: strict;
viele Probleme, wenn der Browser-Support vorhanden ist.
Ein weiterer Kritikpunkt ist, dass Element Queries durch neue Layoutlösungen wie Flexbox oder CSS Grids teilweise überflüssig sind bzw. dass sie nur das Styling betreffen, nicht aber das Verhalten eines Elements. Das stimmt zwar – wäre für mich aber kein Grund nicht trotzdem an der Technologie zu arbeiten, da es haufenweise sinnvolle Anwendungsfälle gibt.
Fazit
Wir sind zwar noch weit entfernt von standardisierten CSS Element Queries – aber das Konzept ist höchst interessant und funktioniert mit JavaScript bereits erstaunlich gut. Ob man sich traut EQs in einem Projekt einzusetzen, muss im Einzelfall entschieden werden, aber es lohnt sich allemal mit der Technologie zu spielen und sie ggf. sogar aktiv mit voranzutreiben.
Der IMHO wichtigste Satz kam em Ende noch, ging aber als Nebensatz etwas unter: „dass Element Queries durch neue Layoutlösungen wie Flexbox oder CSS Grids teilweise überflüssig sind“.
Wenn Entwickler denn anfingen, die Möglichkeiten zu nutzen, die CSS bietet, würden die Rufe nach Features, die CSS (aus Gründen) nicht bietet, leiser werden.
Look Ma, no media queries: https://codepen.io/gunnarbittersmann/pen/jmoWNp
Boah, Gunnar, Du bist echt der Ober-Kommentar-Hooligan.
Wie vergrößerst Du Schlaumeier denn die Schrift dynamisch bei unterschiedlichen Elementgrößen mit Deinen Flexbox und Grid Fähigkeiten? Oder wie änderst die Text-Ausrichtung, je nach Elementgröße? Oder lädst Du andere Hintergrund-Grafiken? Geht nicht. Danke. Weitermachen.
Du hast das Wörtchen „teilweise“ überlesen‽
Das Konzept finde ich auf jeden Fall spannend, selbst wenn wir mit Flexbox mittlerweile ein sehr angenehm zu nutzendes Werkzeug in der Hand haben.
Ich bin gespannt, was ich in dieser Richtung tun wird, im Moment mag ich mich aber noch nicht für einen Ansatz entscheiden.
Viele Grüße
Philipp
Super artikel … Danke!