CSS-Grid-Layout und progressive Verbesserung
Im Frühjahr 2017 wurde erstmals eine große Spezifikation wie Grid nahezu gleichzeitig in Browsern implementiert, und wir haben jetzt Unterstützung für CSS-Grid-Layout in den öffentlichen Versionen von Firefox, Chrome, Opera, Safari und Edge. Während Evergreen-Browser bedeuten, dass viele von uns sehr schnell die Mehrheit der Benutzer mit Grid-Layout-Unterstützung sehen werden, gibt es auch alte oder nicht unterstützende Browser, die berücksichtigt werden müssen. In diesem Leitfaden gehen wir verschiedene Strategien zur Unterstützung durch.
Die unterstützenden Browser
CSS-Grid-Layout ist in allen modernen Browsern unprefixed. Die Unterstützung für alle in diesen Leitfäden beschriebenen Eigenschaften und Werte ist zwischen den Browsern interoperabel. Das bedeutet, dass wenn Sie ein Grid-Layout in Firefox schreiben, es auf die gleiche Weise in Chrome funktionieren sollte. Dies ist keine experimentelle Spezifikation mehr, und Sie können sie sicher in der Produktion verwenden.
Ist es sicher, CSS-Grid für mein Layout zu verwenden?
Ja. Wie bei jeder Frontend-Technologie hängt die Entscheidung, CSS-Grid-Layout zu verwenden, von den Browsern ab, die Ihre Website-Besucher typischerweise verwenden.
Beginnen Sie, Grid in der Produktion zu verwenden
Es ist erwähnenswert, dass Sie Grid nicht auf eine Alles-oder-nichts-Weise verwenden müssen. Beginnen Sie damit, Elemente in Ihrem Design mit Grid zu verbessern, die ansonsten mit einer älteren Methode angezeigt werden könnten. Das Überschreiben von Legacy-Methoden mit Grid-Layout funktioniert überraschend gut, da Grid mit diesen anderen Methoden interagiert.
Floats
Floats wurden früher verwendet, um Layouts mit mehreren Spalten zu erstellen. Wenn Sie einen alten Codebestand mit Floats-Layouts unterstützen, wird es keinen Konflikt geben. Grid-Items ignorieren die float
-Eigenschaft; Fakt ist, dass ein Grid-Item Vorrang hat. Im folgenden Beispiel habe ich ein einfaches Medienobjekt. Wenn der float
nicht aus Legacy-CSS entfernt wird, ist das in Ordnung, da das Container ein Grid-Container ist. Wir können die in CSS-Grids implementierten Ausrichtungseigenschaften verwenden.
Der float
gilt nicht mehr, und ich kann die CSS-Box-Ausrichtungseigenschaft align-self
verwenden, um mein 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 Bild unten zeigt das Medienobjekt in einem nicht unterstützenden Browser links und einem unterstützenden rechts:
Verwenden von Feature-Queries
Das obige Beispiel ist sehr einfach, und wir kommen ohne Code aus, der in Browsern, die Grid nicht unterstützen, ein Problem darstellt, und Legacy-Code ist für unsere Grid-unterstützenden Browser kein Problem. Allerdings sind die Dinge nicht immer so einfach.
Ein komplexeres Beispiel
In diesem nächsten Beispiel habe ich eine Reihe von gefloateten Karten. Ich habe den Karten eine width
zugewiesen, um sie zu float
. Um Lücken zwischen den Karten zu schaffen, verwende ich einen 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 zeigt das typische Problem, das wir mit Float-Layouts haben: Wenn einem der Karten zusätzlicher Inhalt hinzugefügt wird, bricht das Layout.
Als Zugeständnis für ä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!
Dann verbessere ich das Layout mit Grid. Ich kann mein <ul>
in einen Grid-Container mit drei Spalten-Tracks verwandeln. Allerdings gilt die Breite, die ich den Listenelementen selbst zugewiesen habe, weiterhin, und sie macht diese Elemente jetzt zu einem Drittel der Breite des Tracks:
Wenn ich die Breite auf auto
zurücksetze, wird das Float-Verhalten für ältere Browser verhindert. 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 sehr vertraut erscheinen, wenn Sie jemals eine Media Query verwendet haben, um ein responsives Layout zu erstellen. Anstatt eine Viewport-Breite oder ein Browser- beziehungsweise Gerätefeature zu überprüfen, prüfen wir die Unterstützung eines CSS-Eigenschafts- und Wertepaars 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 ältere Layout erforderlich ist.
@supports (display: grid) {
.wrapper {
/* do anything for grid supporting browsers here. */
}
}
Feature Queries haben eine ausgezeichnete Browser-Unterstützung, und alle Browser, die die aktualisierte Grid-Spezifikation unterstützen, unterstützen auch Feature Queries. Sie können sie verwenden, um das Problem zu lösen, das wir mit unserem erweiterten Floating-Layout haben.
Ich verwende eine @supports
-Regel, um die Unterstützung von display: grid
zu überprüfen. Ich mache dann mein Grid-Code auf dem <ul>
, setze meine Breite und min-height
auf dem <li>
auf auto
. Ich entferne auch die Margins und negativen Margins und ersetze den Abstand durch die gap
-Eigenschaft. Das bedeutet, dass in der letzten Zeile von Boxen keine Endmarge mehr auftritt. Das Layout funktioniert jetzt, selbst wenn in einer der Karten mehr Inhalt vorhanden ist, als in den anderen:
.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 aus Elementen mit Floats würden viele von uns eine andere Methode als die oben gezeigte Floating-Methode verwenden, um ein Satz von Karten zu layouten. Die Verwendung von 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 ich muss nicht alles überschreiben. Ein Element, das auf inline-block
gesetzt ist, wird zu einem Grid-Item, und daher gilt das Verhalten von inline-block
nicht mehr. Ich habe die vertical-align
-Eigenschaft auf meinem Element verwendet, wenn es im inline-block
-Modus angezeigt wird, aber diese Eigenschaft gilt nicht für Grid-Items und wird daher ignoriert, sobald das Element zu einem Grid-Item 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 ist es die Breite des Elements, die wir ansprechen müssen, und dann andere Eigenschaften, die wir verbessern möchten. In diesem Beispiel habe ich erneut gap
anstelle von Margins und negativen Margins verwendet, um meine Abstände zu erstellen.
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-Item wird. Die wichtigsten Abschnitte der Spezifikation sind:
Da dieses Verhalten in der Spezifikation beschrieben ist, können Sie sich darauf verlassen, diese Überschreibungen zur Unterstützung älterer 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 detailliert beschreibt.
Andere Werte von Display
Wenn ein Element einen Elternteil mit display: grid
hat, wird es blockified, wie in der CSS-Display-Spezifikation definiert. Im Falle unseres auf inline-block
gesetzten Items ist dies der Grund, warum display: inline-block
nicht mehr gilt.
Wenn Sie display: table
für Ihr Legacy-Layout verwenden, generiert ein auf display: table-cell
gesetztes Element anonyme Boxen. Wenn Sie also display: table-cell
verwenden, ohne dass ein übergeordnetes Element auf display-table
gesetzt ist, wird ein anonymer Tabellen-Wrapper um alle angrenzenden Zellen erstellt, genau so, als hätten Sie sie in ein div oder ein anderes auf display: table
gesetztes Element eingewickelt. Wenn Sie ein Element auf display: table-cell
gesetzt haben und dann in einer Feature-Query den Eltern auf display: grid
ändern, wird diese anonyme Box-Erstellung nicht stattfinden. Das bedeutet, Sie können display: table
-basierte Layouts überschreiben, ohne zusätzliche anonyme Boxen zu haben.
Gefloatete Elemente
Vertikale Ausrichtung
Die Ausrichtungseigenschaft vertical-align
hat keine Auswirkung auf ein Grid-Item. In Layouts mit display: inline-block
oder display: table
könnten Sie die Ausrichtungseigenschaft verwenden, um eine Grundausrichtung durchzuführen. In Ihrem Grid-Layout haben Sie dann die weitaus mächtigeren Box-Ausrichtungs-Eigenschaften.
Layout mit mehreren Spalten
Sie können auch mehrspaltiges Layout als Ihre Legacy-Browser-Planung verwenden, da die column-*
Eigenschaften nicht angewendet werden, wenn sie auf einen Grid-Container angewendet werden.