CSS display: contents;
Mit CSS display: contents; können HTML-Elemente ignoriert werden, wodurch es einfacher wird semantisch korrekte CSS-Layouts zu erstellen.
Als Frontend-Designer steht man ab und zu vor dem Problem, dass die semantisch beste HTML-Struktur mit CSS nicht in die gewünschte Form gebracht werden kann. Oft werden daher Abstriche im HTML-Markup in Kauf genommen. Dieser Fall tritt auch dann ein, wenn Layout-Techniken wie Flexbox oder Grid genutzt werden. Mit dem CSS-Befehl display: contents;
gehören solche Schwierigkeiten der Vergangenheit an.
Beispiel-Layout
Die Funktionsweise von display: contents;
lässt sich an einem anschaulichen Beispiel am besten verdeutlichen. Das folgende Layout soll aufgebaut werden:
Die Herausforderung besteht darin, dass sowohl alle drei farbigen Header-Bereiche der Cards, sowie auch die drei Inhaltsbereiche gleich hoch sein sollen – auch wenn sie unterschiedlich viel Inhalt besitzen. Aus semantischer Sicht, muss natürlich auch der HTML-Code logisch aufgebaut sein.
Folgender HTML-Code ist gewünscht:
<main class="container">
<section class="box">
<header class="box-header"> … </header>
<p class="box-content"> … </p>
</section>
<section class="box">
<header class="box-header"> … </header>
<p class="box-content"> …</p>
</section>
<section class="box">
<header class="box-header"> … </header>
<p class="box-content">… </p>
</section>
</main>
Mit Flexbox und Grid lassen sich nun zwar die drei Boxen (.box
) auf eine Höhe bringen, nicht aber die drei Header innerhalb der Boxen. Das hängt damit zusammen, dass die drei Header (.box-header
) keine Geschwisterelemente sind, die Boxen hingegen schon.
Einfach wäre es, wenn der HTML-Code wie folgt aussähe und es die umschließenden Boxen nicht gäbe:
<main class="container">
<header class="box-header"> … </header>
<p class="box-content"> … </p>
<header class="box-header"> … </header>
<p class="box-content"> …</p>
<header class="box-header"> … </header>
<p class="box-content">… </p>
</main>
Aus semantischer Sicht ist der obige Code zwar inakzeptabel, aber nun lässt sich mit CSS-Grid sehr einfach das Layout konstruieren.
.container {
display: grid;
grid-template-rows: auto auto;
grid-template-columns: repeat(3, 1fr);
grid-auto-flow: column;
grid-gap: 0 1em;
}
Zu Erklärung: Für den .container
wird ein CSS Grid mit zwei Zeilen und drei Spalten aktiviert. Die beiden Zeilen haben eine automatische Höhe, wodurch alle .box-header
und alle .box-content
sich am enthaltenen Inhalt orientieren und immer gleich hoch dargestellt werden. Die drei Spalten haben jeweils eine Breite von 1fr
, wodurch auch diese gleich breit dargestellt werden. Mit grid-auto-flow: column;
wird festgelegt, dass Elemente spaltenbasiert – von oben nach unten – im Grid angeordnet werden. Der Abstand zwischen den Boxen wird durch grid-gap
erzeugt.
Der folgende Screenshot aus den Chrome DevTools visualisiert den Aufbau noch einmal, eine detaillierte Einführung zum Thema CSS Grid findet ihr hier.
Funktionsweise von display: contents;
Das oben beschriebene Beispiel zeigt, dass das gewünschte Layout grundsätzlich sehr unkompliziert ist, allerdings nur wenn Abstriche in der HTML-Semantik gemacht würden. Es versteht sich von selbst, dass wir sowohl die bestmögliche HTML-Semantik als auch ein unkompliziertes CSS-Layout möchten. Genau hier kommt display: contents;
ins Spiel.
Wenn display: contents;
auf ein Element angewendet wird, werden alle Inhalte des Elements so dargestellt, als gäbe es den öffnenden und den schließende HTML-Befehl des Elements nicht. display: contents;
macht daher immer dann besonders viel Sinn, wenn das Element selbst kein sichtbares Styling besitzt.
Genau das ist in unserem Beispiel der Fall. Die drei .box
-Elemente, müssen aus struktureller HTML-Sicht vorhanden sein, sollen für das CSS-Layout aber nicht existieren.
Lösung mit display: contents;
Der gewünschte HTML-Code des Beispiels sieht somit wieder wie zu Beginn aus:
<main class="container">
<section class="box">
<header class="box-header"> … </header>
<p class="box-content"> … </p>
</section>
<section class="box">
<header class="box-header"> … </header>
<p class="box-content"> …</p>
</section>
<section class="box">
<header class="box-header"> … </header>
<p class="box-content">… </p>
</section>
</main>
Mit angewendetem display: contents;
auf den .box
-Elementen ist das Layout kein Problem. Die .box
-Elemente werden nun vom CSS-Layout ignoriert, wodurch sich alle enthaltenen Elemente (.box-header
und .box-content
) wie Geschwisterelemente verhalten.
.container {
display: grid;
grid-template-rows: auto auto;
grid-template-columns: repeat(3, 1fr);
grid-auto-flow: column;
grid-gap: 0 1em;
}
.box {
display: contents;
}
Browser Support
Den detaillierten Browser-Support für dieses Feature könnt ihr auf caniuse.com einsehen.
Hi Jonas,
vielen Dank für das zusammenstellen dieses Artikels. Deine Infos haben uns echt geholfen für einen Kunden exakt die gewünschte UI umzusetzen. Zum Glück handelte es sich um eine interne Webanwendung und der Kunde hatte erstmal nur Wert auf Chrome gelegt ;)
Ja, ich wollte das gleiche wie Sven erwähnen – display: content; in einer kleinen Anzahl von Browsern korrekt angezeigt wird, während die Elemente in den meisten Browsern korrekt angezeigt werden.
Hi Jonas,
danke für die Erklärung. Das wäre genau das Richtige, um ein derzeitiges Problem in einem Webprojekt zu lösen, wenn da nicht die Browserkompatibilität wäre. Wir haben es rein gebaut und lösen den Rest mit dem bereits erwähnten Javascript Hack.
Schönes Beispiel, was sicherlich in der Praxis öfters mal vorkommt. Problem ist natürlich, das display: contents Global nur von 13% der Browser unterstützt wird. Somit muss man aktuell noch anders an die Sach herangehen. Eventuell über eine min-height am header-Element. Das ist natürlich dann nicht so dynamisch.
Alternativ kann man natürlich auch per JavaScript die Höhe dynamisch anpassen, bis der Browser-Support von display: contents; dann ausreichend ist.
Hallo Sven,
zu aller erst, das Beispiel finde ich sehr gut erklärt. Das nur „13%“ der Browser contents unterstützt ist an sich ja kein Problem. Es nutzt ja so gut wie jeder Chrome / Firefox / Edge (eher weniger).