CSS Grid-Layout und progressive Verbesserung
Im Frühjahr 2017 sahen wir erstmalig, dass eine große Spezifikation wie Grid nahezu gleichzeitig in Browsern implementiert wurde, und wir haben nun CSS Grid-Layout-Unterstützung in den öffentlichen Versionen von Firefox, Chrome, Opera, Safari und Edge. Obwohl Evergreen-Browser bedeuten, dass viele von uns die Mehrheit der Benutzer schnell mit Grid-Layout-Unterstützung sehen werden, gibt es auch alte oder nicht unterstützende Browser zu berücksichtigen. In diesem Leitfaden gehen wir verschiedene Strategien zur Unterstützung durch.
Die unterstützenden Browser
Das CSS Grid-Layout ist in allen modernen Browsern ohne Präfixe verfügbar. Die Unterstützung für alle in diesen Leitfäden detaillierten Eigenschaften und Werte ist über die Browser hinweg interoperabel. Das bedeutet, dass, wenn Sie Grid-Layout-Code in Firefox schreiben, er in Chrome auf dieselbe Weise funktionieren sollte. Dies ist keine experimentelle Spezifikation mehr, und Sie können sie sicher in der Produktion verwenden.
Ist es sicher, CSS Grids für mein Layout zu verwenden?
Ja. Wie bei jeder Front-End-Technologie wird die Entscheidung, das CSS Grid-Layout zu verwenden, von den Browsern abhängen, die Ihre Site-Besucher typischerweise verwenden.
Beginn der Nutzung von Grid in der Produktion
Es ist erwähnenswert, dass Sie nicht gezwungen sind, Grid auf eine Alles-oder-Nichts Weise zu verwenden. Beginnen Sie damit, Elemente in Ihrem Design mit Grid zu verbessern, die ansonsten mit einer älteren Methode dargestellt werden könnten. Das Überschreiben von Legacy-Methoden mit Grid-Layout funktioniert überraschend gut aufgrund der Art und Weise, wie Grid mit diesen anderen Methoden interagiert.
Floats
Floats wurden früher verwendet, um mehrspaltige Layouts zu erstellen. Wenn Sie eine alte Codebasis mit Float-Layouts unterstützen, gibt es keinen Konflikt. Grid-Elemente ignorieren die Float-Eigenschaft; die Tatsache ist, dass ein Grid-Element Vorrang hat. Im folgenden Beispiel habe ich ein einfaches Medienobjekt. Wenn das float
nicht aus dem Legacy-CSS entfernt wird, da der Container ein Grid-Container ist, ist das in Ordnung. Wir können die Ausrichtungseigenschaften verwenden, die in CSS Grids implementiert sind.
Das float
gilt nicht mehr, und ich kann die CSS Box-Alignment-Eigenschaft align-self
verwenden, um meinen Inhalt am Ende des Containers auszurichten:
* {
box-sizing: border-box;
}
img {
max-width: 100%;
display: block;
}
.media {
border: 2px solid #f76707;
border-radius: 5px;
background-color: #fff4e6;
max-width: 400px;
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-areas: "img content";
margin-bottom: 1em;
}
.media::after {
content: "";
display: block;
clear: both;
}
.media .text {
padding: 10px;
align-self: end;
}
/* old code we can't remove */
.media .image {
float: left;
width: 150px;
margin-right: 20px;
}
<div class="media">
<div class="image">
<img src="https://dummyimage.com/150x150" alt="placeholder" />
</div>
<div class="text">
This is a media object example. I am using floats for older browsers and
grid for new ones.
</div>
</div>
Das folgende Bild zeigt das Medienobjekt in einem nicht unterstützenden Browser links und einem unterstützenden rechts:
Verwendung von Feature-Queries
Das obige Beispiel ist sehr einfach und wir kommen ohne die Notwendigkeit aus, Code zu schreiben, der für Browser, die Grid nicht unterstützen, ein Problem darstellen würde, und Legacy-Code ist kein Problem für unsere Grid-unterstützenden Browser. Allerdings sind die Dinge nicht immer so einfach.
Ein komplexeres Beispiel
Im nächsten Beispiel habe ich eine Reihe von Karten mit Floats. Ich habe den Karten eine width
gegeben, um sie zu float
. Um Lücken zwischen den Karten zu schaffen, verwende ich eine margin
auf den Elementen und dann einen negativen Rand auf dem Container:
.wrapper ul {
overflow: hidden;
margin: 0 -10px;
padding: 0;
list-style: none;
}
.wrapper li {
float: left;
width: calc(33.333333% - 20px);
margin: 0 10px 20px 10px;
}
<div class="wrapper">
<ul>
<li class="card">
<h2>One</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Two</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Three</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Four</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Five</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Six</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
</ul>
</div>
Das Beispiel demonstriert das typische Problem, das wir mit Float-Layouts haben: Wenn zusätzlicher Inhalt zu einer der Karten hinzugefügt wird, bricht das Layout.
Als Zugeständnis an ältere Browser habe ich den Elementen eine min-height
zugewiesen und hoffe, dass meine Inhaltsredakteure nicht zu viel Inhalt hinzufügen und das Layout durcheinanderbringen!
Anschließend verbessere ich das Layout mit Grid. Ich kann mein <ul>
in einen Grid-Container mit drei Spalten verwandeln. Die von mir zugewiesene Breite für die Listenelemente selbst bleibt jedoch bestehen und macht diese Elemente nun ein Drittel so breit wie das Track:
Wenn ich die Breite auf auto
setze, wird dieses Verhalten in älteren Browsern nicht mehr auftreten. Ich muss in der Lage sein, die Breite für ältere Browser zu definieren und die Breite für Grid-unterstützende Browser zu entfernen. Dank CSS Feature Queries kann ich dies direkt in meinem CSS tun.
Eine Lösung mit Feature-Queries
Feature-Queries werden Ihnen sehr vertraut vorkommen, wenn Sie jemals eine Media Query verwendet haben, um ein responsives Layout zu erstellen. Anstatt eine Viewport-Breite oder ein Merkmal des Browsers oder Geräts zu überprüfen, prüfen wir die Unterstützung eines CSS-Eigenschafts- und Wertpaar mit einer @supports
-Regel. Innerhalb der Feature-Query können wir dann beliebiges CSS schreiben, das wir benötigen, um unser modernes Layout anzuwenden und alles zu entfernen, was für das alte Layout erforderlich ist.
@supports (display: grid) {
.wrapper {
/* do anything for grid supporting browsers here. */
}
}
Feature-Queries haben hervorragende Browser-Unterstützung, und alle Browser, die die aktualisierte Grid-Spezifikation unterstützen, unterstützen auch Feature-Queries. Sie können sie verwenden, um mit dem Problem umzugehen, das wir mit unserem verbesserten Float-Layout haben.
Ich verwende eine @supports
-Regel, um die Unterstützung von display: grid
zu prüfen. Ich benutze dann meinen Grid-Code auf <ul>
, setze meine Breite und min-height
auf <li>
auf auto
. Ich entferne auch die Ränder und die negativen Ränder und ersetze die Abstände durch die gap
-Eigenschaft. Das bedeutet, dass ich keinen endgültigen Rand auf der letzten Reihe von Boxen habe. Das Layout funktioniert jetzt, auch wenn in einer der Karten mehr Inhalt als in den anderen vorhanden ist:
.wrapper ul {
overflow: hidden;
margin: 0 -10px;
padding: 0;
list-style: none;
}
.wrapper li {
float: left;
width: calc(33.333333% - 20px);
margin: 0 10px 20px 10px;
}
@supports (display: grid) {
.wrapper ul {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin: 0;
}
.wrapper li {
width: auto;
min-height: auto;
margin: 0;
}
}
<div class="wrapper">
<ul>
<li class="card">
<h2>One</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Two</h2>
<p>We can use CSS grid to overwrite older methods.</p>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Three</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Four</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Five</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Six</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
</ul>
</div>
Überschreiben anderer Werte von display
Aufgrund der Probleme bei der Erstellung von Grids mit Float-Elementen würden viele von uns eine andere Methode als die oben gezeigte Float-Methode verwenden, um ein Set von Karten zu layouten. display: inline-block
ist eine alternative Methode.
Auch hier kann ich Feature-Queries verwenden, um ein Layout zu überschreiben, das display: inline-block
verwendet, und auch hier muss ich nicht alles überschreiben. Ein Element, das auf inline-block
gesetzt ist, wird zu einem Grid-Element, und das Verhalten von inline-block
gilt nicht mehr. Ich habe die Eigenschaft vertical-align
an meinem Element verwendet, wenn es sich im Modus inline-block
befindet, aber diese Eigenschaft gilt nicht für Grid-Elemente und wird daher ignoriert, sobald das Element zu einem Grid-Element wird:
.wrapper ul {
margin: 0 -10px;
padding: 0;
list-style: none;
}
.wrapper li {
display: inline-block;
vertical-align: top;
width: calc(33.333333% - 20px);
margin: 0 10px 20px 10px;
}
@supports (display: grid) {
.wrapper ul {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin: 0;
}
.wrapper li {
width: auto;
margin: 0;
}
}
<div class="wrapper">
<ul>
<li class="card">
<h2>One</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Two</h2>
<p>We can use CSS grid to overwrite older methods.</p>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Three</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Four</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Five</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Six</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
</ul>
</div>
Wieder einmal ist es die Breite des Elements, die wir ansprechen müssen, und dann alle anderen Eigenschaften, die wir verbessern möchten. In diesem Beispiel habe ich erneut gap
verwendet, anstatt Ränder und negative Ränder zu verwenden, um meine Abstände zu erzeugen.
Wie definiert die Spezifikation diese Überschreibungen?
Die CSS Grid-Layout-Spezifikation beschreibt, warum wir das Verhalten bestimmter Eigenschaften überschreiben können, wenn etwas zu einem Grid-Element wird. Die Schlüsselabschnitte der Spezifikation sind:
Da dieses Verhalten in der Spezifikation beschrieben wird, können Sie sich sicher darauf verlassen, diese Überschreibungen in Ihrer Unterstützung für ältere Browser zu verwenden. Nichts, was hier beschrieben wird, sollte als "Hack" angesehen werden. Vielmehr nutzen wir die Tatsache, dass die Grid-Spezifikation die Interaktion zwischen verschiedenen Layout-Methoden beschreibt.
Andere Werte von display
Wenn ein Element ein Elternteil hat, das auf display: grid
gesetzt ist, wird es gemäß der CSS Display-Spezifikation blockifiziert. Im Falle unseres Elements auf inline-block
ist dies der Grund, warum display: inline-block
nicht mehr angewendet wird.
Wenn Sie display: table
für Ihr Legacy-Layout verwenden, generiert ein auf display: table-cell
gesetztes Element anonyme Boxen. Wenn Sie display: table-cell
ohne ein Elternteil verwenden, das auf display-table
gesetzt ist, wird ein anonymer Tabellen-Wrapper um alle angrenzenden Zellen erstellt, so als ob Sie sie in ein div oder ein anderes Element gesetzt hätten, das auf display: table
gesetzt ist. Wenn Sie ein auf display: table-cell
gesetztes Element haben und dann in einer Feature-Query das Elternteil auf display: grid
ändern, wird diese anonyme Boxenerstellung nicht stattfinden. Das bedeutet, dass Sie display: table
basierte Layouts überschreiben können, ohne zusätzliche anonyme Boxen zu haben.
Floated-Elemente
Vertikale Ausrichtung
Die Ausrichtungseigenschaft vertical-align
hat keine Wirkung auf ein Grid-Element. In Layouts, die display: inline-block
oder display: table
verwenden, könnten Sie die Eigenschaft vertical-align für grundlegende Ausrichtungszwecke verwenden. In Ihrem Grid-Layout haben Sie dann die weitaus leistungsfähigeren Box-Alignment-Eigenschaften.
Mehrspalten-Layout
Sie können auch ein Mehrspalten-Layout als Ihren Plan für veraltete Browser verwenden, da die column-*
Eigenschaften nicht wirksam sind, wenn sie auf einen Grid-Container angewendet werden.