Erkundung der impliziten Raster- und Auto-Platzierungs-Fähigkeiten von CSS Grid

Avatar of Temani Afif
Temani Afif am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Bei der Arbeit mit CSS Grid besteht der erste Schritt darin, display: grid auf das Element anzuwenden, das zu einem Grid-Container werden soll. Dann definieren wir das Grid explizit durch eine Kombination aus grid-template-columns, grid-template-rows und grid-template-areas. Von dort aus ist der nächste Schritt, Elemente im Grid zu platzieren.

Dies ist der klassische Ansatz, der verwendet werden sollte und den ich auch empfehle. Es gibt jedoch einen anderen Ansatz zum Erstellen von Grids ohne explizite Definition. Wir nennen dies das implizite Grid.

„Explizit, implizit? Was zum Teufel geht hier vor sich?“

Seltsame Begriffe, richtig? Manuel Matuzovic hat bereits eine gute Erklärung dafür, was wir mit „implizit“ und „explizit“ in CSS Grid meinen, aber tauchen wir direkt in das ein, was die Spezifikation sagt

Die Eigenschaften grid-template-rows, grid-template-columns und grid-template-areas definieren eine feste Anzahl von Spuren, die das explizite Grid bilden. Wenn Grid-Elemente außerhalb dieser Grenzen platziert werden, generiert der Grid-Container implizite Grid-Spuren, indem er implizite Grid-Linien zum Grid hinzufügt. Diese Linien bilden zusammen mit dem expliziten Grid das implizite Grid.

Im Klartext bedeutet das, dass der Browser automatisch zusätzliche Zeilen und Spalten generiert, falls Elemente außerhalb des definierten Grids platziert werden.

Was ist mit der automatischen Platzierung?

Ähnlich wie beim Konzept des impliziten Grids ist die automatische Platzierung die Fähigkeit des Browsers, Elemente automatisch im Grid zu platzieren. Wir müssen nicht immer die Position jedes Elements angeben.

Durch verschiedene Anwendungsfälle werden wir sehen, wie solche Funktionen uns helfen können, komplexe und dynamische Grids mit wenigen Codezeilen zu erstellen.

Dynamische Seitenleiste

Hier haben wir drei verschiedene Layouts, aber nur eine Grid-Konfiguration, die für alle funktioniert.

main {
  display: grid;
  grid-template-columns: 1fr;
}

Nur eine Spalte nimmt den gesamten freien Platz ein. Dies ist unser „explizites“ Grid. Es ist so eingerichtet, dass ein Grid-Element in den main Grid-Container passt. Das ist alles. Eine Spalte und eine Zeile.

Aber was wäre, wenn wir beschließen, ein weiteres Element hinzuzufügen, sagen wir ein aside (unsere dynamische Seitenleiste). Wie es derzeit (und explizit) definiert ist, muss sich unser Grid automatisch anpassen, um einen Platz für dieses Element zu finden. Und wenn wir sonst nichts mit unserem CSS machen, zeigt uns DevTools Folgendes:

Das Element nimmt die gesamte Spalte ein, die explizit auf dem Container gesetzt ist. In der Zwischenzeit fällt es in eine neue Zeile zwischen implizite Grid-Linien mit den Bezeichnungen 2 und 3. Beachten Sie, dass ich einen 20px Abstand verwende, um die Dinge visuell zu trennen.

Wir können die <aside> in eine Spalte neben der <section> verschieben

aside {
  grid-column-start: 2;
}

Und hier ist, was DevTools uns jetzt sagt

Das Element befindet sich zwischen der ersten und zweiten Grid-Spaltenlinie des Grid-Containers. Die beginnt an der zweiten Grid-Spaltenlinie und endet an einer dritten Linie, die wir nie deklariert haben.

Wir platzieren unser Element in der zweiten Spalte, aber… wir haben keine zweite Spalte. Seltsam, oder? Wir haben keine zweite Spalte auf dem <main> Grid-Container deklariert, aber der Browser hat eine für uns erstellt! Dies ist der Kernpunkt aus der Spezifikation, die wir uns angesehen haben

Wenn Grid-Elemente außerhalb dieser Grenzen platziert werden, generiert der Grid-Container implizite Grid-Spuren, indem er implizite Grid-Linien zum Grid hinzufügt.

Diese leistungsstarke Funktion ermöglicht uns dynamische Layouts. Wenn wir nur das <section>-Element haben, erhalten wir nur eine Spalte. Aber wenn wir ein <aside>-Element hinzufügen, wird eine zusätzliche Spalte erstellt, um es aufzunehmen.

Wir könnten die <aside> stattdessen vor der <section> platzieren, so:

aside {
  grid-column-end: -2;
} 

Dies erstellt die implizite Spalte am Anfang des Grids, im Gegensatz zum vorherigen Code, der die implizite Spalte am Ende platziert.

Wir können entweder eine rechte oder linke Seitenleiste haben

Wir können dasselbe einfacher tun, indem wir die Eigenschaft grid-auto-flow verwenden, um alle impliziten Spuren in Richtung column fließen zu lassen.

Jetzt ist es nicht mehr nötig, grid-column-start anzugeben, um das <aside>-Element rechts von der <section> zu platzieren! Tatsächlich wird jedes andere Grid-Element, das wir zu irgendeinem Zeitpunkt hinzufügen, nun in Spaltenrichtung fließen, wobei jedes in seiner eigenen impliziten Grid-Spur platziert wird. Perfekt für Situationen, in denen die Anzahl der Elemente im Grid nicht im Voraus bekannt ist!

Das heißt, wir brauchen immer noch grid-column-end, wenn wir es in einer Spalte links davon platzieren wollen, denn sonst nimmt die <aside> die explizite Spalte ein, was wiederum die <section> aus dem expliziten Grid verdrängt und sie zwingt, die implizite Spalte zu übernehmen.

Ich weiß, ich weiß. Das ist ein bisschen verworren. Hier ist ein weiteres Beispiel, das wir verwenden können, um diesen kleinen Eigenart besser zu verstehen.

Im ersten Beispiel haben wir keine Platzierung angegeben. In diesem Fall platziert der Browser zuerst das <aside>-Element in der expliziten Spalte, da es zuerst im DOM steht. Die <section> wird stattdessen automatisch in die Grid-Spalte platziert, die der Browser automatisch (oder implizit) für uns erstellt.

Im zweiten Beispiel haben wir das <aside>-Element außerhalb des expliziten Grids gesetzt.

aside {
  grid-column-end: -2;
}

Jetzt spielt es keine Rolle, dass <aside> zuerst im HTML steht. Indem wir <aside> woanders neu zuweisen, haben wir das <section>-Element verfügbar gemacht, um die explizite Spalte zu übernehmen.

Bild-Grid

Versuchen wir etwas anderes mit einem Bild-Grid, bei dem wir ein großes Bild und ein paar Thumbnails daneben (oder darunter) haben.

Wir haben zwei Grid-Konfigurationen. Aber raten Sie mal? Ich definiere gar kein Grid! Alles, was ich tue, ist dies:

.grid img:first-child {
  grid-area: span 3 / span 3;
}

Es ist überraschend, dass wir nur eine Codezeile brauchen, um so etwas zu realisieren. Lassen Sie uns also untersuchen, was vor sich geht, und Sie werden sehen, dass es einfacher ist, als Sie denken. Erstens ist grid-area eine Kurzschreibweise, die die folgenden Eigenschaften in einer einzigen Deklaration kombiniert:

  • grid-row-start
  • grid-row-end
  • grid-column-start
  • grid-column-end

Moment mal! Ist grid-area nicht die Eigenschaft, die wir verwenden, um benannte Bereiche zu definieren, anstatt wo Elemente im Grid beginnen und enden?

Ja, aber es tut noch mehr. Wir könnten viel mehr über grid-area schreiben, aber in diesem speziellen Fall

.grid img:first-child {
  grid-area: span 3 / span 3;
}

/* ...is equivalent to: */
.grid img:first-child {
  grid-row-start: span 3;
  grid-column-start: span 3;
  grid-row-end: auto;
  grid-column-end: auto;
}

Wir sehen dasselbe, wenn wir DevTools öffnen, um die Kurzschreibweise zu erweitern.

Das bedeutet, dass das erste Bildelement im Grid drei Spalten und drei Zeilen überspannen muss. Aber da wir keine Spalten oder Zeilen definiert haben, macht der Browser das für uns.

Wir haben im Wesentlichen das erste Bild im HTML so platziert, dass es ein 3x3 Grid einnimmt. Das bedeutet, dass alle anderen Bilder automatisch in denselben drei Spalten platziert werden, ohne dass etwas Neues angegeben werden muss.

Zusammenfassend lässt sich sagen, dass wir dem Browser mitgeteilt haben, dass das erste Bild den Platz von drei Spalten und drei Zeilen einnehmen muss, die wir beim Einrichten des Grid-Containers nie explizit definiert haben. Der Browser hat diese Spalten und Zeilen für uns eingerichtet. Infolgedessen fließen die verbleibenden Bilder im HTML direkt an ihren Platz, indem sie dieselben drei Spalten und Zeilen verwenden. Und da das erste Bild alle drei Spalten in der ersten Zeile einnimmt, fließen die verbleibenden Bilder in zusätzliche Zeilen, die jeweils drei Spalten enthalten, wobei jedes Bild eine Spalte einnimmt.

All das mit einer Zeile CSS! Das ist die Kraft des „impliziten“ Grids und der automatischen Platzierung.

Für die zweite Grid-Konfiguration in dieser Demo habe ich lediglich die automatische Flussrichtung mit grid-auto-flow: column geändert, so wie wir es zuvor getan haben, als wir ein <aside>-Element neben einer <section> platziert haben. Dies zwingt den Browser, eine *vierte* Spalte zu erstellen, die er zum Platzieren der übrigen Bilder verwenden kann. Und da wir drei Zeilen haben, werden die übrigen Bilder in derselben vertikalen Spalte platziert.

Wir müssen den Bildern einige Eigenschaften hinzufügen, um sicherzustellen, dass sie gut in das Grid passen, ohne Überläufe zu verursachen.

.grid {
  display: grid;
  grid-gap: 10px;
}

/* for the second grid configuration */
.horizontal {
  grid-auto-flow: column;
}

/* The large 3⨉3 image */
.grid img:first-child {
  grid-area: span 3 / span 3;
}

/* Help prevent stretched or distorted images */
img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

Und natürlich können wir das Grid leicht aktualisieren, um mehr Bilder zu berücksichtigen, indem wir einen Wert anpassen. Das wäre die 3 in den Stilen für das große Bild. Wir haben dies:

.grid img:first-child {
  grid-area: span 3 / span 3;
}

Aber wir könnten einfach eine vierte Spalte hinzufügen, indem wir sie stattdessen in 4 ändern.

.grid img:first-child {
  grid-area: span 4 / span 4;
}

Noch besser: Lassen Sie uns das als benutzerdefinierte Eigenschaft einrichten, um die Dinge noch einfacher zu aktualisieren.

Dynamische Layouts

Der erste Anwendungsfall mit der Seitenleiste war unser erstes dynamisches Layout. Nun werden wir uns komplexeren Layouts widmen, bei denen die Anzahl der Elemente die Grid-Konfiguration bestimmt.

In diesem Beispiel können wir zwischen einem und vier Elementen haben, wobei sich das Grid so anpasst, dass es die Anzahl der Elemente gut aufnimmt, ohne lästige Lücken oder fehlende Bereiche zu hinterlassen.

Wenn wir ein Element haben, tun wir nichts. Das Element dehnt sich aus, um die einzige Zeile und Spalte zu füllen, die automatisch vom Grid erstellt wird.

Aber wenn wir das zweite Element hinzufügen, erstellen wir eine weitere (implizite) Spalte mit grid-column-start: 2.

Wenn wir ein drittes Element hinzufügen, sollte es die Breite von zwei Spalten einnehmen – deshalb haben wir grid-column-start: span 2 verwendet, aber nur, wenn es das :last-child ist, denn wenn (und wenn) wir ein viertes Element hinzufügen, sollte dieses nur eine Spalte einnehmen.

Zusammenfassend haben wir vier Grid-Konfigurationen mit nur zwei Deklarationen und der Magie des impliziten Grids.

.grid {
  display: grid;
}
.grid :nth-child(2) {
  grid-column-start: 2;
}
.grid :nth-child(3):last-child {
  grid-column-start: span 2;
}

Versuchen wir eine weitere.

Wir tun nichts für den ersten und zweiten Fall, in dem wir nur ein oder zwei Elemente haben. Wenn wir jedoch ein drittes Element hinzufügen, sagen wir dem Browser, dass es – solange es das :last-child ist – zwei Spalten überspannen soll. Wenn wir ein viertes Element hinzufügen, sagen wir dem Browser, dass dieses Element in der zweiten Spalte platziert werden muss.

.grid {
  display: grid;
}
.grid :nth-child(3):last-child {
  grid-column-start: span 2;
}
.grid :nth-child(4) {
  grid-column-start: 2;
}

Verstehen Sie den Trick allmählich? Wir geben dem Browser spezifische Anweisungen basierend auf der Anzahl der Elemente (mit :nth-child) und manchmal kann eine Anweisung das Layout komplett verändern.

Es sei darauf hingewiesen, dass die Größenbestimmung nicht dieselbe ist, wenn wir mit unterschiedlichen Inhalten arbeiten.

Da wir keine Größen für unsere Elemente definiert haben, passt der Browser sie automatisch basierend auf ihrem Inhalt an, und wir erhalten möglicherweise eine andere Größenbestimmung als die, die wir gerade gesehen haben. Um dies zu überwinden, müssen wir *explizit* angeben, dass alle Spalten und Zeilen gleich groß sind.

grid-auto-rows: 1fr;
grid-auto-columns: 1fr;

Hey, diese Eigenschaften haben wir noch nicht benutzt! grid-auto-rows und grid-auto-columns setzen die Größe von impliziten Zeilen und Spalten in einem Grid-Container. Oder, wie die Spezifikation erklärt:

Die Eigenschaften grid-auto-columns und grid-auto-rows geben die Größe von Spuren an, denen keine Größe durch grid-template-rows oder grid-template-columns zugewiesen wurde.

Hier ist ein weiteres Beispiel, bei dem wir bis zu sechs Elemente haben können. Dieses Mal überlasse ich Ihnen die Analyse des Codes. Keine Sorge, die Selektoren mögen komplex aussehen, aber die Logik ist ziemlich einfach.

Selbst mit sechs Elementen brauchten wir nur zwei Deklarationen. Stellen Sie sich all die komplexen und dynamischen Layouts vor, die wir mit wenigen Codezeilen erzielen können!

Was passiert mit diesem grid-auto-rows und warum hat es drei Werte? Definieren wir drei Zeilen?

Nein, wir definieren keine drei Zeilen. Aber wir definieren drei Werte als Muster für unsere impliziten Zeilen. Die Logik ist wie folgt:

  • Wenn wir eine Zeile haben, wird sie mit dem ersten Wert bemessen.
  • Wenn wir zwei Zeilen haben, erhält die erste den ersten Wert und die zweite den zweiten Wert.
  • Wenn wir drei Zeilen haben, werden die drei Werte verwendet.
  • Wenn wir vier Zeilen haben (und hier kommt der interessante Teil), verwenden wir die drei Werte für die ersten drei Zeilen und wiederholen den ersten Wert für die vierte Zeile. Deshalb ist es eine Art Muster, das wir wiederholen, um alle impliziten Zeilen zu bemessen.
  • Wenn wir 100 Zeilen haben, werden sie drei nach drei bemessen: 2fr 2fr 1fr 2fr 2fr 1fr 2fr 2fr 1fr usw.

Im Gegensatz zu grid-template-rows, das die Anzahl der Zeilen und ihre Größen definiert, bemisst grid-auto-rows nur Zeilen, die im Laufe der Zeit erstellt werden könnten.

Wenn wir zu unserem Beispiel zurückkehren, ist die Logik, gleiche Größen zu haben, wenn zwei Zeilen erstellt werden (wir verwenden 2fr 2fr), aber wenn eine dritte Zeile erstellt wird, machen wir sie etwas kleiner.

Grid-Muster

Für diese letzte Sache werden wir über Muster sprechen. Sie haben wahrscheinlich diese Zwei-Spalten-Layouts gesehen, bei denen eine Spalte breiter ist als die andere, und jede Zeile wechselt die Platzierung dieser Spalten.

Dieses Art von Layout kann schwierig sein, ohne genau zu wissen, wie viel Inhalt wir haben, aber die Auto-Platzierungs-Fähigkeiten von CSS Grid machen es zu einem relativen Kinderspiel.

Werfen Sie einen Blick auf den Code. Er mag komplex aussehen, aber zerlegen wir ihn, denn er ist letztendlich ziemlich einfach.

Das erste, was zu tun ist, ist, das Muster zu identifizieren. Fragen Sie sich: „Nach wie vielen Elementen sollte sich das Muster wiederholen?“ In diesem Fall ist es nach jedem vierten Element. Betrachten wir also vorerst nur vier Elemente.

Definieren wir nun das Grid und richten wir das allgemeine Muster mit dem :nth-child-Selektor für den Wechsel zwischen den Elementen ein.

.grid {
  display: grid;
  grid-auto-columns: 1fr; /* all the columns are equal */
  grid-auto-rows: 100px; /* all the rows equal to 100px */
}
.grid :nth-child(4n + 1) { /* ?? */ }
.grid :nth-child(4n + 2) { /* ?? */ }
.grid :nth-child(4n + 3) { /* ?? */ }
.grid :nth-child(4n + 4) { /* ?? */ }

Wir sagten, dass sich unser Muster alle vier Elemente wiederholt, also verwenden wir logischerweise 4n + x, wobei x von 1 bis 4 reicht. Es ist etwas einfacher, das Muster auf diese Weise zu erklären.

4(0) + 1 = 1 = 1st element /* we start with n = 0 */
4(0) + 2 = 2 = 2nd element
4(0) + 3 = 3 = 3rd element
4(0) + 4 = 4 = 4th element
4(1) + 1 = 5 = 5th element /* our pattern repeat here at n = 1 */
4(1) + 2 = 6 = 6th element
4(1) + 3 = 7 = 7th element
4(1) + 4 = 8 = 8th element
4(2) + 1 = 9 = 9th element /* our pattern repeat again here at n = 2 */
etc.

Perfekt, oder? Wir haben vier Elemente und wiederholen das Muster beim fünften Element, dem neunten Element und so weiter.

Diese :nth-child-Selektoren können knifflig sein! Chris hat eine super hilfreiche Erklärung, wie das alles funktioniert, einschließlich Rezepten zur Erstellung verschiedener Muster.

Nun konfigurieren wir jedes Element so, dass

  1. Das erste Element muss zwei Spalten einnehmen und bei Spalte eins beginnen (grid-column: 1/span 2).
  2. Das zweite Element wird in der dritten Spalte platziert (grid-column-start: 3).
  3. Das dritte Element wird in der ersten Spalte platziert: (grid-column-start: 1).
  4. Das vierte Element nimmt zwei Spalten ein und beginnt bei der zweiten Spalte: (grid-column: 2/span 2).

Hier ist das in CSS:

.grid {
  display: grid;
  grid-auto-columns: 1fr; /* all the columns are equal */
  grid-auto-rows: 100px; /* all the rows are equal to 100px */
}
.grid :nth-child(4n + 1) { grid-column: 1/span 2; }
.grid :nth-child(4n + 2) { grid-column-start: 3; }
.grid :nth-child(4n + 3) { grid-column-start: 1; }
.grid :nth-child(4n + 4) { grid-column: 2/span 2; }

Wir könnten hier aufhören und fertig sein… aber wir können es besser machen! Insbesondere können wir einige Deklarationen entfernen und uns auf die Auto-Platzierungs-Fähigkeiten von Grid verlassen, um die Arbeit für uns zu erledigen. Dies ist der kniffligste Teil zum Begreifen und erfordert viel Übung, um zu erkennen, was entfernt werden kann.

Das Erste, was wir tun können, ist, grid-column: 1 /span 2 zu aktualisieren und nur grid-column: span 2 zu verwenden, da der Browser standardmäßig das erste Element in die erste Spalte platziert. Wir können auch dies entfernen.

.grid :nth-child(4n + 3) { grid-column-start: 1; }

Indem wir das erste, zweite und vierte Element platzieren, platziert das Grid das dritte Element automatisch an der richtigen Stelle. Das bedeutet, dass wir Folgendes übrig haben:

.grid {
  display: grid;
  grid-auto-rows: 100px; /* all the rows are equal to 100px */
  grid-auto-columns: 1fr; /* all the columns are equal */
}
.grid :nth-child(4n + 1) { grid-column: span 2; }
.grid :nth-child(4n + 2) { grid-column-start: 3; }
.grid :nth-child(4n + 4) { grid-column: 2/span 2; }

Aber komm schon, wir können es noch besser machen! Wir können auch dies entfernen.

.grid :nth-child(4n + 2) { grid-column-start: 3; }

Warum? Indem wir das vierte Element in der zweiten Spalte platzieren und es zwei volle Spalten einnehmen lassen, zwingen wir das Grid, eine dritte implizite Spalte zu erstellen, was uns insgesamt drei Spalten ergibt, ohne es explizit anzuweisen. Das vierte Element kann nicht in die erste Zeile gelangen, da das erste Element ebenfalls zwei Spalten einnimmt, sodass es in die nächste Zeile fließt. Diese Konfiguration hinterlässt uns eine leere Spalte in der ersten Zeile und eine leere in der zweiten Zeile.

Ich glaube, Sie kennen das Ende der Geschichte. Der Browser platziert die zweite und dritte Element automatisch in diese leeren Stellen. Unsere Code wird also noch einfacher.

.grid {
  display: grid;
  grid-auto-columns: 1fr; /* all the columns are equal */
  grid-auto-rows: 100px; /* all the rows are equal to 100px */
}
.grid :nth-child(4n + 1) { grid-column: span 2; }
.grid :nth-child(4n + 4) { grid-column: 2/span 2; }

Alles, was es braucht, sind fünf Deklarationen, um ein sehr cooles und sehr flexibles Muster zu erstellen. Der Optimierungsteil kann knifflig sein, aber man gewöhnt sich daran und gewinnt mit Übung einige Tricks.

Warum nicht grid-template-columns verwenden, um explizite Spalten zu definieren, da wir die Anzahl der Spalten kennen?

Das können wir tun! Hier ist der Code dafür:

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* all the columns are equal */
  grid-auto-rows: 100px; /* all the rows are equal to 100px */
}
.grid :nth-child(4n + 1),
.grid :nth-child(4n + 4) {
  grid-column: span 2;
}

Wie Sie sehen, ist der Code definitiv intuitiver. Wir definieren drei explizite Grid-Spalten und sagen dem Browser, dass das erste und vierte Element zwei Spalten einnehmen müssen. Ich empfehle diesen Ansatz dringend! Aber das Ziel dieses Artikels ist es, neue Ideen und Tricks zu erkunden, die wir durch die impliziten und Auto-Platzierungs-Fähigkeiten von CSS Grid erhalten.

Der explizite Ansatz ist geradliniger, während ein implizites Grid Sie erfordert – entschuldigen Sie das Wortspiel – die Lücken zu füllen, wo CSS im Hintergrund zusätzliche Arbeit leistet. Am Ende glaube ich, dass ein solides Verständnis von impliziten Grids Ihnen helfen wird, den CSS Grid-Algorithmus besser zu verstehen. Schließlich sind wir nicht hier, um das Offensichtliche zu studieren – wir sind hier, um wilde Gebiete zu erkunden!

Versuchen wir ein weiteres Muster, diesmal etwas schneller.

Unser Muster wiederholt sich alle sechs Elemente. Das dritte und vierte Element müssen jeweils zwei volle Zeilen einnehmen. Wenn wir das dritte und vierte Element platzieren, scheint es, dass wir uns nicht um die anderen kümmern müssen. Versuchen wir also Folgendes:

.grid {
  display: grid;
  grid-auto-columns: 1fr;
  grid-auto-rows: 100px;
}
.grid :nth-child(6n + 3) {
  grid-area: span 2/2; /* grid-row-start: span 2 && grid-column-start: 2 */
}
.grid :nth-child(6n + 4) {
  grid-area: span 2/1; /* grid-row-start: span 2 && grid-column-start: 1 */
}

Hmm, das ist nicht gut. Wir müssen das zweite Element in der ersten Spalte platzieren. Andernfalls platziert das Grid es automatisch in der zweiten Spalte.

.grid :nth-child(6n + 2) {
  grid-column: 1; /* grid-column-start: 1 */
}

Besser, aber es gibt noch mehr Arbeit. Wir müssen das dritte Element nach oben verschieben. Es ist verlockend, zu versuchen, es auf diese Weise in der ersten Zeile zu platzieren.

.grid :nth-child(6n + 3) {
  grid-area: 1/2/span 2; 
    /* Equivalent to:
       grid-row-start: 1;
       grid-row-end: span 2;
       grid-column-start: 2 
     */
}

Aber das funktioniert nicht, weil es alle 6n + 3 Elemente zwingt, im selben Bereich platziert zu werden, was zu einem durcheinandergeratenen Layout führt. Die eigentliche Lösung besteht darin, die anfängliche Definition des dritten Elements beizubehalten und grid-auto-flow: dense hinzuzufügen, um die Lücken zu füllen. Von MDN

[Der] „dichte“ Packalgorithmus versucht, Lücken früher im Grid zu füllen, wenn später kleinere Elemente auftreten. Dies kann dazu führen, dass Elemente aus der Reihenfolge geraten, wenn dies Lücken füllt, die von größeren Elementen hinterlassen wurden. Wenn es weggelassen wird, wird ein „spärlicher“ Algorithmus verwendet, bei dem der Platzierungsalgorithmus beim Platzieren von Elementen nur „vorwärts“ im Grid geht und niemals zurückspringt, um Lücken zu füllen. Dies stellt sicher, dass alle automatisch platzierten Elemente „in Reihenfolge“ erscheinen, auch wenn dadurch Lücken entstehen, die von späteren Elementen hätten gefüllt werden können.

Ich weiß, dass diese Eigenschaft nicht sehr intuitiv ist, aber vergessen Sie sie niemals, wenn Sie auf ein Platzierungsproblem stoßen. Bevor Sie vergeblich verschiedene Konfigurationen ausprobieren, fügen Sie sie hinzu, da sie Ihr Layout möglicherweise ohne zusätzlichen Aufwand behebt.

Warum nicht immer diese Eigenschaft standardmäßig hinzufügen?

Ich empfehle es nicht, weil wir in manchen Fällen dieses Verhalten nicht wünschen. Beachten Sie, wie die Erklärung von MDN erwähnt, dass Elemente „außer der Reihenfolge“ fließen, um Lücken zu füllen, die von größeren Elementen hinterlassen wurden. Die visuelle Reihenfolge ist normalerweise genauso wichtig wie die Quellreihenfolge, insbesondere wenn es um zugängliche Schnittstellen geht, und grid-auto-flow: dense kann manchmal zu einer Diskrepanz zwischen der visuellen und der Quellreihenfolge führen.

Unser endgültiger Code ist dann:

.grid {
  display: grid;
  grid-auto-columns: 1fr;
  grid-auto-flow: dense;
  grid-auto-rows: 100px;
}
.grid :nth-child(6n + 2) { grid-column: 1; }
.grid :nth-child(6n + 3) { grid-area: span 2/2; }
.grid :nth-child(6n + 4) { grid-row: span 2; }

Noch eins? Los geht's!

Dazu werde ich nicht viel sagen, sondern Ihnen stattdessen eine Illustration des von mir verwendeten Codes zeigen. Versuchen Sie zu sehen, ob Sie verstehen, wie ich zu diesem Code gekommen bin.

Die schwarzen Elemente werden implizit im Grid platziert. Es sei darauf hingewiesen, dass wir dasselbe Layout auf mehr als eine Weise erreichen können, als wie ich dorthin gelangt bin. Können Sie diese auch herausfinden? Was ist mit der Verwendung von grid-template-columns? Teilen Sie Ihre Arbeiten im Kommentarbereich.

Ich hinterlasse Ihnen noch ein letztes Muster.

Ich habe eine Lösung dafür, aber Sie sind an der Reihe zu üben. Nehmen Sie alles, was wir gelernt haben, und versuchen Sie, dies selbst zu kodieren und dann mit meiner Lösung zu vergleichen. Machen Sie sich keine Sorgen, wenn Sie mit etwas Ausführlichem enden – das Wichtigste ist, eine funktionierende Lösung zu finden.

Möchten Sie mehr?

Bevor wir enden, möchte ich ein paar Stack Overflow-Fragen zu CSS Grid teilen, bei denen ich mit Antworten eingestiegen bin, die viele der hier gemeinsam behandelten Techniken verwenden. Es ist eine gute Liste, die zeigt, wie viele reale Anwendungsfälle und reale Situationen vorkommen, in denen diese Dinge nützlich sind.

Zusammenfassung

CSS Grid gibt es seit Jahren, aber es gibt immer noch viele wenig bekannte und wenig genutzte Tricks, die nicht weit verbreitet diskutiert werden. Das implizite Grid und die Auto-Platzierungsfunktionen sind zwei davon!

Und ja, das kann herausfordernd werden! Es hat mich viel Zeit gekostet, die Logik hinter impliziten Grids zu durchdringen, und mit der Auto-Platzierung habe ich immer noch zu kämpfen. Wenn Sie mehr Zeit damit verbringen möchten, sich mit expliziten und impliziten Grids auseinanderzusetzen, sind hier ein paar zusätzliche Erklärungen und Beispiele, die es wert sind, angesehen zu werden.

Ebenso möchten Sie vielleicht über grid-auto-columns im CSS-Tricks Almanac lesen, da Mojtaba Seyedi sehr detailliert darauf eingeht und unglaublich hilfreiche visuelle Darstellungen zur Erklärung des Verhaltens enthält.

Wie ich am Anfang sagte, sollen die hier behandelten Methoden die gängigen Methoden, die Sie bereits zum Erstellen von Grids kennen, nicht ersetzen. Ich erkunde lediglich verschiedene Wege, die in einigen Fällen hilfreich sein können.