Verwendung von benannten Grid-Bereichen zur Visualisierung (und Referenzierung) Ihres Layouts

Avatar of Preethi Selvam
Preethi Selvam am

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

Immer wenn wir einfache oder komplexe Layouts mit CSS Grid erstellen, positionieren wir Elemente normalerweise mit Zeilennummern. Grid-Layouts enthalten Grid-Linien, die automatisch mit positiven und negativen Zeilennummern indiziert werden (es sei denn, wir benennen sie explizit). Das Positionieren von Elementen mit Zeilennummern ist eine gute Möglichkeit, Dinge anzuordnen, obwohl CSS Grid zahlreiche Möglichkeiten bietet, dasselbe mit einer geringeren kognitiven Belastung zu erreichen. Eine dieser Methoden ist das, was ich gerne als "ASCII"-Methode bezeichne.

Die ASCII-Methode in Kürze

Die Methode läuft darauf hinaus, grid-template-areas zu verwenden, um Grid-Elemente mithilfe von benutzerdefinierten benannten Bereichen auf der Ebene des Grid-Containers anstelle von Zeilennummern zu positionieren.

Wenn wir ein Element mit display: grid als Grid-Container deklarieren, generiert der Grid-Container standardmäßig eine einzelne Spaltenspur und Zeilen, die ausreichen, um die Grid-Elemente aufzunehmen. Die Kindelemente des Containers, die am Grid-Layout beteiligt sind, werden unabhängig von ihrer display-Eigenschaft zu Grid-Elementen.

Erstellen wir zum Beispiel ein Grid, indem wir Spalten und Zeilen explizit mit den Eigenschaften grid-template-columns und grid-template-rows definieren.

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(3, 200px);
}

Dieser kleine CSS-Schnipsel erstellt ein 3×2-Grid, bei dem die Grid-Elemente die gleiche Breite in den Spalten einnehmen und bei dem das Grid drei Zeilen mit einer Spurengröße von 200px enthält.

Wir können das gesamte Layout mit benannten Grid-Bereichen mithilfe der Eigenschaft grid-template-areas definieren. Laut der Spezifikation ist der anfängliche Wert von grid-template-areas none.

grid-template-areas = none | <string>+

<string>+ listet die Gruppe von Zeichenfolgen auf, die mit einem Anführungszeichen umschlossen sind. Jede Zeichenfolge wird als Zelle dargestellt, und jede Anführungszeichen-umschlossene Zeichenfolge wird als Zeile dargestellt. So

grid-template-areas: "head head" "nav main" "foot foot";

Der Wert von grid-template-areas beschreibt das Layout als vier Grid-Bereiche. Diese sind:

  • head
  • nav
  • main
  • foot

head und foot erstrecken sich über zwei Spaltenspuren und eine Zeilenspur. Die verbleibenden nav und main nehmen jeweils eine Spaltenspur und eine Zeilenspur ein. Der Wert von grid-template-areas ähnelt stark dem Anordnen von ASCII-Zeichen, und wie Chris vor einiger Zeit vorschlug, können wir eine Visualisierung der Gesamtstruktur des Layouts direkt aus dem CSS erhalten, was der unkomplizierteste Weg ist, es zu verstehen.

(GIF in voller Größe)

Okay, wir haben unser Layout mit vier benannten Grid-Bereichen erstellt: head, nav, main, foot.

Lassen Sie uns nun damit beginnen, die Grid-Elemente anhand von benannten Grid-Bereichen anstelle von Zeilennummern zu positionieren. Insbesondere platzieren wir ein header-Element im benannten Grid-Bereich head und geben den benannten Grid-Bereich head im header-Element über die grid-area-Eigenschaft an.

Benannte Grid-Bereiche in einem Grid-Layout werden als idents bezeichnet. Wir haben also gerade ein benutzerdefiniertes ident namens head erstellt, das wir verwenden können, um Elemente in bestimmten Grid-Spuren zu platzieren.

header { grid-area: head; }

Wir können andere HTML-Elemente mit anderen benutzerdefinierten idents verwenden

nav { grid-area: nav; }
main { grid-area: main; }
footer { grid-area: foot; }

Schreiben von Werten für benannte Bereiche

Laut CSS Grid Layout Module Level 1 müssen alle Zeichenfolgen unter den folgenden Tokens definiert werden

  • Benannter Zellen-Token: Repräsentiert den benannten Grid-Bereich im Grid. Zum Beispiel ist head ein benannter Zellen-Token.
  • Null-Zellen-Token: Repräsentiert den unbenannten Grid-Bereich im Grid-Container. Zum Beispiel ist eine leere Zelle im Grid ein Null-Zellen-Token.
  • Trash-Token: Dies ist ein Syntaxfehler, z. B. eine ungültige Deklaration. Zum Beispiel würde eine unterschiedliche Anzahl von Zellen und Zeilen im Vergleich zur Anzahl der Grid-Elemente eine Deklaration ungültig machen.

In grid-template-area muss jede Anführungszeichen-umschlossene Zeichenfolge (die Zeilen) die gleiche Anzahl von Zellen haben und das vollständige Grid definieren, ohne Zellen zu ignorieren.

Wir können eine Zelle ignorieren oder sie als leere Zelle belassen, indem wir das Punktzeichen (.) verwenden.

.grid { 
  display: grid;
  grid-template-areas:
    "head head"
    "nav main"
    "foot .";
}

Wenn sich das für Sie visuell seltsam oder unausgewogen anfühlt, können wir mehrere Punktzeichen ohne Leerzeichen dazwischen verwenden.

.grid {
  display: grid;
  grid-template-areas:
    "head head"
    "nav main"
    "foot ....";
}

Ein benannter Zellen-Token kann mehrere Grid-Zellen umfassen. Diese Zellen müssen jedoch ein rechteckiges Layout bilden. Mit anderen Worten, wir können keine "L"- oder "T"-förmigen Layouts erstellen, obwohl die Spezifikation auf Unterstützung für nicht-rechteckige Layouts mit getrennten Bereichen in der Zukunft hinweist.

ASCII ist besser als zeilenbasierte Platzierung

Zeilenbasierte Platzierung bedeutet, dass wir die Eigenschaften grid-column und grid-row verwenden, um ein Element im Grid mithilfe von Grid-Liniennummern zu positionieren, die automatisch nummerisch indiziert werden.

.grid-item {
  grid-column: 1 / 3; /* start at grid column line 1 and span to line 3 */
}

Aber die Zeilennummern von Grid-Elementen können sich ändern, wenn sich unser Layout an einem Breakpoint ändert. In diesen Fällen können wir uns nicht auf die gleichen Zeilennummern verlassen, die wir an einem bestimmten Breakpoint verwendet haben. Hier erfordert es zusätzliche kognitive Belastung, den Code zu verstehen.

Deshalb denke ich, dass ein ASCII-basierter Ansatz am besten funktioniert. Wir können das Layout für jeden Breakpoint mit grid-template-areas innerhalb des Grid-Containers neu definieren, was eine praktische visuelle Darstellung des Layouts direkt im CSS bietet – es ist wie selbstdokumentierender Code!

.grid {
  grid-template-areas:
    "head head"
    "nav main"
    "foot ...."; /* much easier way to see the grid! */
}

.grid-item {
  grid-area: foot; /* much easier to place the item! */
}

Wir können die Zeilennummern und Grid-Bereiche eines Grids tatsächlich in den DevTools sehen. Gehen Sie in Firefox zum Beispiel zum Layout-Panel. Aktivieren Sie dann unter dem Tab Grid die Optionen „Grid-Anzeigeeinstellungen“ und „Zeilennummern anzeigen“ und „Bereichsnamen anzeigen“.

Enabling grid settings.

Dieser ASCII-Ansatz mit benannten Bereichen erfordert weniger Aufwand zur Visualisierung und zum einfachen Auffinden der Platzierung von Elementen.

Line-based placement versus ASCII Art placement.

Betrachten wir den „universellen“ Anwendungsfall

Immer wenn ich ein Tutorial über benannte Grid-Bereiche sehe, ist das übliche Beispiel im Allgemeinen ein Layoutmuster, das header, main, sidebar und footer Bereiche enthält. Ich denke gerne an diesen als den „universellen“ Anwendungsfall, da er ein so breites Feld abdeckt.

The Holy Grail layout in rectangles.

Es ist ein großartiges Beispiel, um zu veranschaulichen, wie grid-template-areas funktioniert, aber eine reale Implementierung beinhaltet normalerweise Media Queries, die so eingestellt sind, dass sie das Layout bei bestimmten Ansichtsfensterbreiten ändern. Anstatt grid-area für jedes Grid-Element bei jedem Breakpoint neu deklarieren zu müssen, um alles neu zu positionieren, können wir grid-template-areas verwenden, um auf den Breakpoint zu „reagieren“ – und dabei eine schöne visuelle Darstellung des Layouts bei jedem Breakpoint erhalten!

Bevor wir das Layout definieren, weisen wir jedem Element mit der Eigenschaft grid-area als Basisstil ein ident zu.

header {
  grid-area: head;
}

.left-side {
  grid-area: left;
}

main {
  grid-area: main;
}

.right-side {
  grid-area: right;
}

footer {
  grid-area: foot;
}

Nun definieren wir das Layout erneut als Basisstil. Wir gehen nach dem Mobile-First-Ansatz vor, sodass sich die Dinge standardmäßig stapeln.

.grid-container {
  display: grid;
  grid-template-areas:
    "head"
    "left"
    "main"
    "right"
    "foot";
}

Jedes Grid-Element ist in dieser Konfiguration automatisch dimensioniert – was ein wenig seltsam erscheint –, sodass wir min-height: 100vh auf dem Grid-Container setzen können, um mehr Spielraum zu haben.

.grid-container {
  display: grid;
  grid-template-areas:
    "head"
    "left"
    "main"
    "right"
    "foot";
  min-height: 100vh;
}

Nehmen wir nun an, wir möchten, dass sich das main-Element rechts von den gestapelten left- und right-Seitenleisten befindet, wenn wir zu einem etwas breiteren Ansichtsfenster gelangen. Wir deklarieren grid-template-areas mit einem aktualisierten ASCII-Layout, um dies zu erreichen.

@media (min-width: 800px) {
  .parent {
    grid-template-columns: 0.5fr 1fr;
    grid-template-rows: 100px 1fr 1fr 100px;
    grid-template-areas:
      "head head"
      "left main"
      "right main"
      "foot foot";
  }
}

Ich habe einige Spalten- und Zeilengrößen rein zur Ästhetik hinzugefügt.

Wenn der Browser noch breiter wird, möchten wir das Layout möglicherweise wieder ändern, sodass main zwischen den left- und right-Seitenleisten liegt. Schreiben wir das Layout visuell!

.grid-container {
  grid-template-columns: 200px 1fr 200px; /* again, just for sizing */
  grid-template-areas:
    "head head head"
    "left main right"
    "left main right"
    "foot foot foot";
}

Nutzung impliziter Zeilennamen für Flexibilität

Laut der Spezifikation generiert grid-template-areas automatisch Namen für die Grid-Linien, die von benannten Grid-Bereichen erzeugt werden. Wir nennen diese implizit benannten Grid-Linien, weil sie für uns kostenlos benannt werden, ohne zusätzliche Arbeit.

Jeder benannte Grid-Bereich erhält vier implizit benannte Grid-Linien, zwei in Spaltenrichtung und zwei in Zeilenrichtung, wobei -start und -end an das ident angehängt werden. Zum Beispiel erhält ein Grid-Bereich namens head head-start und head-end Linien in beiden Richtungen, insgesamt vier implizit benannte Grid-Linien.

Implicitly assigned line names.

Wir können diese Linien zu unserem Vorteil nutzen! Wenn wir beispielsweise möchten, dass ein Element die Bereiche main, left und right unseres Grids überlagert. Zuvor haben wir darüber gesprochen, wie Layouts rechteckig sein müssen – keine "T"- und "L"-förmigen Layouts erlaubt. Daher können wir die ASCII-Visualisierungsmethode nicht verwenden, um die Überlagerung zu platzieren. Wir können jedoch unsere impliziten Zeilennamen mit derselben grid-area-Eigenschaft für die Überlagerung verwenden, die wir zur Positionierung der anderen Elemente verwenden.

Wussten Sie, dass grid-area eine Kurzschrifteigenschaft ist, ähnlich wie margin und padding Kurzschrifteigenschaften sind? Sie nimmt mehrere Werte auf dieselbe Weise entgegen, aber anstatt einer „Uhrzeigerrichtung“ wie bei margin – die in der Reihenfolge margin-block-start, margin-inline-end, margin-block-end und margin-inline-start erfolgt – geht grid-area so:

grid-area: block-start / inline-start / block-end / inline-end;
Showing the block and inline flow directions in a left-to-right writing mode.

Aber wir sprechen über Zeilen und Spalten, nicht über Block- und Inline-Richtungen, richtig? Nun, sie entsprechen einander. Die Zeilenachse entspricht der Blockrichtung, und die Spaltenachse entspricht der Inline-Richtung.

grid-area: grid-row-start / grid-column-start / grid-row-end / grid-column-end;
Block and inline axis.

Zurück zur Positionierung des Überlagerungselements als Grid-Element in unserem Layout. Die Eigenschaft grid-area wird hilfreich sein, um das Element mit unseren implizit benannten Grid-Linien zu positionieren.

.overlay {
  grid-area: left-start / left-start / right-end / main-end;
}

Erstellung eines minimalen Grid-Systems

Wenn wir uns auf Layouts wie den gerade gesehenen „universellen“ Anwendungsfall konzentrieren, ist es verlockend, Grid-Bereiche als einen Bereich pro Element zu betrachten. Aber es muss nicht so funktionieren. Wir können idents wiederholen, um mehr Platz für sie im Layout zu reservieren. Das haben wir im letzten Beispiel gesehen, als wir die idents head und foot wiederholt haben.

.grid-container {
  grid-template-areas:
    "head head head"
    "left main right"
    "left main right"
    "foot foot foot";
}

Beachten Sie, dass main, left und right ebenfalls wiederholt werden, aber in Blockrichtung.

Vergessen wir die Full-Page-Layouts und verwenden wir benannte Grid-Bereiche für eine Komponente. Grid eignet sich genauso gut für Komponenten-Layouts wie für Full Pages!

Hier ist eine ziemlich Standard-Hero-Komponente mit einer Reihe von Bildern, gefolgt von verschiedenen Textblöcken.

A row of weightlifting photos above a heading, blurb, then a row of three links.

Der HTML ist ziemlich einfach.

<div class="hero">
  <div class="image">
    <img src="..." alt="" />
  </div>
  <div class="text">
    <!-- ... -->
  </div>
</div>

Wir könnten das für ein sehr schnelles gestapeltes Layout machen.

.hero {
  grid-template-areas:
    "image"
    "text";
}

Aber dann müssen wir padding, max-width oder etwas anderes verwenden, um den Textbereich schmaler als die Bildreihe zu machen. Wie wäre es, wenn wir unser ASCII-Layout stattdessen zu einem Vier-Spalten-Grid erweitern, indem wir unsere idents auf beiden Zeilen wiederholen?

.hero {
  display: grid;
  grid-template-columns: repeat(4, 1fr); /* maintain equal sizing */
  grid-template-areas:
    "image image image image"
    "text  text  text  text";
}

Okay, jetzt können wir unsere Grid-Elemente in diese benannten Bereiche platzieren.

.hero .image {
  grid-area: image;
}

.hero .text {
  grid-area: text;
}

Bisher alles gut – beide Zeilen nehmen die gesamte Breite ein. Das können wir als Basislayout für kleine Bildschirme verwenden.

Showing grid lines on the stacked mobile version of the page.

Aber vielleicht möchten wir den schmaleren Text einführen, wenn das Ansichtsfenster eine größere Breite erreicht. Wir können das, was wir über das Punktzeichen wissen, verwenden, um Spalten zu „überspringen“. Nehmen wir an, das text-Ident überspringt in diesem Fall die erste und die letzte Spalte.

@media (min-width: 800px) {
  main {
    grid-template-columns: repeat(6, 1fr); /* increase to six columns */
    grid-template-areas:
      "image image image image image image"
      "..... text  text  text  text  .....";
  }
}

Jetzt haben wir den gewünschten Abstand.

Showing grid lines for a table-sized layout of the page.

Wenn das Layout bei noch größeren Breakpoints weitere Anpassungen benötigt, können wir weitere Spalten hinzufügen und von dort aus weitermachen.

.hero {
  grid-template-columns: repeat(8, 1fr);
  grid-template-areas:
    "image image image image image image image image"
    "..... text  text  text  text  text  text  .....";
}

Dev-Tool-Visualisierung

Showing grid lines for a large table sized layout of the page.

Erinnern Sie sich, als 12-Spalten- und 16-Spalten-Layouts die großen Dinge in CSS-Frameworks waren? Wir können schnell auf dieses Niveau skalieren und ein schönes visuelles ASCII-Layout im Code beibehalten.

main {
  grid-template-columns: repeat(12, 1fr);
  grid-template-areas:
    "image image image image image image image image image image image image"
    "..... text  text  text  text  text  text  text  text  text  text  .....";
}

Betrachten wir etwas Komplexeres

Wir haben ein ziemlich generisches Beispiel und ein relativ einfaches Beispiel betrachtet. Mit komplexeren Layouts können wir immer noch schöne ASCII-Layout-Visualisierungen erhalten.

Arbeiten wir uns zu diesem vor.

Three images positioned around a fancy heading.

Ich habe dies in zwei Elemente im HTML unterteilt, einen header und einen main.

<header>
  <div class="logo"> ... </div>
  <div class="menu"> ... </div>
</header>
<main>
  <div class="image"> ... </div>
  <h2> ... </h2>
  <div class="image"> ... </div>
  <div class="image"> ... </div>
</main>

Ich denke, Flexbox ist für den header besser geeignet, da wir seine Kindelemente so leichter verteilen können. Also kein grid dort.

header {
  display: flex;
  justify-content: space-between;
  /* etc. */
}

Aber grid eignet sich gut für das Layout des main-Elements. Definieren wir das Layout und weisen wir die idents den entsprechenden Elementen zu, die wir benötigen, um die drei .image-Elemente und den .text zu positionieren. Wir beginnen damit als Basis für kleine Bildschirme.

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-areas:
    "image1 image1 .....  image2"
    "texts  texts  texts  texts"
    ".....  image3 image3 .....";
}

Sie sehen bereits, worauf wir hinauswollen, richtig? Das Layout wird für uns visualisiert, und wir können die Grid-Elemente mit den benutzerdefinierten idents an ihren Platz setzen.

.image:nth-child(1) {
  grid-area: image1;
}

.image:nth-last-child(2) {
  grid-area: image2;
}

.image:nth-last-child(1) {
  grid-area: image3;
}

h2 {
  grid-area: texts;
}
Showing grid lines on a mobile layout of the page.

Das ist unser Basislayout, also wagen wir uns an einen breiteren Breakpoint.

@media (min-width: 800px) {
  .grid {
    grid-template-columns: repeat(8, 1fr);
    grid-template-areas:
      ". image1 image1 ...... ......  ...... image2 ."
      ". texts  texts  texts  texts   texts  image2 ."
      ". .....  image3 image3 image3  image3 ...... .";
  }
}

Ich wette, Sie wissen jetzt genau, wie das aussehen wird, weil das Layout direkt im Code steht!

Showing grid lines for a table-sized layout of the page.

Dasselbe gilt, wenn wir uns entscheiden, noch weiter zu skalieren.

.grid {
  grid-template-columns: repeat(12, 1fr);
  grid-template-areas:
    ". image1 image1 .....  .....   .....  .....  .....  .....  .....  .....  ."
    ". texts  texts  texts  texts   texts  texts  texts  texts  texts  image2 ."
    ". .....  image3 image3 image3  image3 .....  .....  .....  .....  .....  .";
}
Showing grid lines for a desktop-sized layout of the page.

Hier ist die vollständige Demo.

Ich verwende den „Negative margin Hack“, damit das erste Bild den Header überlappt.

Zusammenfassung

Ich bin neugierig, ob sonst noch jemand grid-template-areas verwendet, um benannte Bereiche zu erstellen, um eine ASCII-Visualisierung des Grid-Layouts zu erhalten. Dies als Referenz in meinem CSS-Code zu haben, hat einige sonst komplexe Designs entmystifiziert, die bei der Arbeit mit Zeilennummern möglicherweise noch komplexer gewesen wären.

Aber wenn nichts anderes, lehrt uns die Definition von Grid-Layouts auf diese Weise einige interessante Dinge über CSS Grid, die wir in diesem Beitrag gesehen haben.

  • Die Eigenschaft grid-template-areas ermöglicht es uns, benutzerdefinierte idents – oder „benannte Bereiche“ – zu erstellen und sie zur Positionierung von Grid-Elementen mit der Eigenschaft grid-area zu verwenden.
  • Es gibt drei Arten von „Tokens“, die grid-template-areas als Werte akzeptiert, darunter benannte Zellen-Tokens, Null-Zellen-Tokens und Trash-Tokens.
  • Jede Zeile, die in grid-template-areas definiert ist, muss die gleiche Anzahl von Zellen haben. Das Ignorieren einer einzelnen Zelle erzeugt kein Layout; es wird als Trash-Token betrachtet.
  • Wir können ein visuelles ASCII-ähnliches Diagramm des Grid-Layouts im Wert der Eigenschaft grid-template-areas erhalten, indem wir erforderliche Leerzeichen zwischen benannten Zellen-Tokens verwenden, während wir das Grid-Layout definieren.
  • Stellen Sie sicher, dass sich innerhalb eines Null-Zellen-Tokens keine Leerzeichen befinden (z. B. .....). Andernfalls erzeugt ein einzelnes Leerzeichen zwischen Null-Zellen-Tokens unnötige leere Zellen, was zu einem ungültigen Layout führt.
  • Wir können das Layout an verschiedenen Breakpoints neu definieren, indem wir die Grid-Elemente mit grid-area neu positionieren und dann das Layout mit grid-template-areas auf dem Grid-Container neu deklarieren, um die Spurenliste bei Bedarf zu aktualisieren. Die Grid-Elemente müssen nicht angefasst werden.
  • Benutzerdefinierte benannte Grid-Bereiche erhalten automatisch vier implizit zugewiesene Zeilennamen – <custom-ident>-start und <custom-ident>-end sowohl in Spalten- als auch in Zeilenrichtung.