Vertikale Ausrichtung erreichen (Danke, Subgrid!)

Avatar of Cathy Dutton
Cathy Dutton am

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

Unsere Werkzeuge für vertikale Ausrichtung sind in letzter Zeit viel besser geworden. Meine frühen Tage als Webdesignerin bestanden darin, 960px breite Homepage-Designs zu layouten und Dinge horizontal über eine Seite mit einem 12-Spalten-Raster auszurichten. Media Queries kamen auf, was eine ernsthafte mentale Umstellung erforderte. Sie lösten natürlich einige große Probleme, führten aber auch neue ein, wie z. B. die Ausrichtung, wenn Elemente umbrechen oder anderweitig im Layout verschoben werden. 

Schauen wir uns ein bestimmtes Szenario an: eine "Leiste" mit einigen Schaltflächen darin. Es gibt zwei Gruppen dieser Schaltflächen, die jeweils in einem <fieldset> mit einer <legend> enthalten sind. 

Auf einem großen Bildschirm sind wir bereit

Two groups of two bright pink buttons set on a dark background.

Und hier ist eine sehr einfache CSS-Methode, die dieses Layout erreicht und bei einem mobilen Breakpoint auch auf zwei "Zeilen" aufbricht

.accessibility-tools fieldset {
  width: 48%;
  float: left;
  margin-right: 1%;
}


/* Mobile */
@media only screen and (max-width: 480px) {
  .accessibility-tools fieldset {
    width: 100%;
  }
}

Auf einem kleinen Bildschirm erhalten wir dies

The same two groups of two pink buttons, with one group of buttons stacked on top of the other, showing the buttons are uneven in width.

Das ist das Problem: fehlende vertikale Ausrichtung. Nehmen wir an, wir möchten diese Schaltflächen zu einer angenehmeren Anordnung ausrichten, bei der sich die Schaltflächenkanten schön aneinander ausrichten.

Um zu beginnen, könnten wir uns für feste, pixelbasierte CSS-Lösungen entscheiden, um Elemente bei verschiedenen Breakpoints schön auszurichten, indem wir Magische Zahlen wie diese verwenden

/* Mobile */
@media only screen and (max-width: 480px) {
  legend {
    width: 160px;
  }
  button {
    width: 130px;
  }
}
the same two groups of pink buttons but where the buttons all have the same consistent width and line up evenly.

Das erledigt die Sache.

Aber... das ist nicht gerade eine flexible Lösung für das Problem. Abgesehen von den magischen Zahlen (feste Pixelwerte basierend auf spezifischem Inhalt) stützte es sich auch auf die Verwendung von Media Queries, von denen ich mich, wann immer möglich, entfernen möchte. Dies habe ich in einem Beitrag mit dem Titel "Stepping away from Sass" auf meinem Blog diskutiert.

Als ich mich moderneren CSS-Funktionen zuwandte, wurde die Notwendigkeit, bestimmte Bildschirmgrößen mit eindeutigem Code anzusprechen, beseitigt.

Was ich brauche, ist, dass jede Schaltfläche und jedes Label reagiert

  1. auf den verfügbaren Platz
  2. ihren Inhalt 

und!

  1. andere Elemente um sie herum.

Verfügbarer Platz

Das Problem bei der Verwendung von Media Queries ist, dass sie den umgebenden Platz der neu ausgerichteten Elemente nicht berücksichtigen – ein Punkt, der in diesem Bild aus "The Flexbox holy albatross" von Heydon Pickering perfekt demonstriert wird.

Three browsers side-by-side. The first shows three black rectangles in a single row, the second shows three black rectangles stacked vertically, and the third shows three black rectangles set to the right hand of the screen.

Was ich wirklich will, ist, dass das zweite <fieldset> unter das erste umbricht, *nur wenn sie nicht mehr ordentlich auf eine Zeile passen.*

Können wir das mit Flexbox erreichen?

Ein Hauptverkaufsargument für Flexbox ist seine Fähigkeit, Elemente zu erstellen, die auf den umgebenden Platz reagieren. Komponenten können "flexen", um zusätzlichen Platz zu füllen und schrumpfen, um in kleinere Räume zu passen. 

Für diese Situation ist die Eigenschaft flex-wrap auf wrap gesetzt. Das bedeutet, sobald beide <fieldset>-Elemente nicht mehr auf eine Zeile passen, werden sie auf eine zweite Zeile umgebrochen.

.wrapper--accessibility-tools {
  display: flex;
  flex-wrap: wrap;
} 

Die Eigenschaft flex-wrap hat drei verfügbare Werte. Der Standardwert ist nowrap, wodurch Elemente auf einer Zeile bleiben. Der Wert wrap erlaubt es Elementen, auf mehrere Zeilen zu fließen. Dann gibt es noch wrap-reverse, das es Elementen erlaubt, umzubrechen, aber – warten Sie – in *umgekehrter Reihenfolge* (es ist seltsam zu sehen: wenn Elemente umbrechen, gehen sie in Links-nach-Rechts-Situationen über die vorherige Zeile).

Die Verwendung von Flexbox macht das Layout weniger starr, aber ein min-width-Wert ist immer noch erforderlich, um das Problem der vertikalen Ausrichtung zu beheben. Also: nah dran, aber noch nicht ganz.

Kann Grid uns helfen?

CSS Grid ist das allererste CSS-Modul, das speziell entwickelt wurde, um die anhaltenden Layoutprobleme zu lösen, mit denen Webdesigner und -entwickler konfrontiert sind. Es ist kein direkter Ersatz für Flexbox; vielmehr arbeiten die beiden Module normalerweise ziemlich gut zusammen.

Wie Flexbox kann Grid verwendet werden, um jedem <fieldset> so viel oder so wenig Platz wie nötig einzunehmen. Um gleich zur Sache zu kommen, können wir die Schlüsselwörter auto-fill und auto-fit (innerhalb einer repeat()-Funktion) nutzen, damit Grid-Elemente auf mehreren Zeilen fließen, ohne dass Media Queries erforderlich sind. Der Unterschied ist etwas subtil, aber gut erklärt in "Auto-Sizing Columns in CSS Grid: auto-fill vs auto-fit" von Sara Soueidan. Nehmen wir auto-fit.

.wrapper--accessibility-tools {
  display: grid;
  grid-template-columns: repeat(auto-fit, 450px);
  grid-gap: 10px;
}

Ähnlich wie im Flexbox-Beispiel muss ich immer noch einen absoluten Wert für die Breite des Labels festlegen, um die <fieldset>-Elemente beim Stapeln auszurichten.

Ein weiterer Ansatz mit Grid

CSS Grid erlaubt es Elementen auch, basierend auf ihrem Inhalt mit flexiblen Grid-Spuren zu reagieren. Zusätzlich zu anderen Längeneinheiten wie Prozent, relativen Einheiten oder Pixel akzeptiert CSS Grid eine Fractional Unit (fr), wobei 1fr einen Teil des verfügbaren Platzes einnimmt, 2fr zwei Teile des verfügbaren Platzes einnimmt und so weiter. Richten wir hier zwei gleiche Spalten ein.

.wrapper--accessibility-tools {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 10px;
}

Es gibt auch eine minmax()-Funktion, die Grid-Spuren erstellt, die sich an den verfügbaren Platz anpassen, aber auch nicht schmaler als eine angegebene Größe werden.

.wrapper--accessibility-tools {
  display: grid;
  grid-template-columns: minmax(auto, max-content) minmax(auto, max-content);
  grid-gap: 10px;
}

Beide Demos funktionieren und sind frei von absoluten Werten oder gerätespezifischem CSS. Die Ergebnisse sind jedoch weit von ideal entfernt, jede Grid-Struktur reagiert an unterschiedlichen Punkten. Vielleicht kein großes Problem, aber sicherlich nicht optimal.

Dies geschieht, weil beim Hinzufügen von display: grid zu einem Container nur die direkten Kinder dieses Containers zu Grid-Elementen werden. Das bedeutet, dass die von uns verwendeten intrinsischen Größeneinheiten nur auf Elemente im selben Grid bezogen sind. 

Subgrid verwenden

Um mein Ziel wirklich zu erreichen, muss ich, dass die Schaltflächen und Labels auf Elemente in Geschwister-Grid-Containern reagieren. CSS Grid Level 2 beinhaltet die Subgrid-Funktion. Obwohl wir schon immer Grids verschachteln konnten, waren die Elemente in jedem Grid-Container unabhängig. Mit Subgrid können wir verschachtelte (Child-)Grids einrichten, die die Spuren von Elterngrid-Grids verwenden.

Dies macht viele zuvor schwierige Muster viel einfacher, insbesondere das "Card"-Muster, das das beliebteste Beispiel zu sein scheint, um die Vorteile von Subgrid zu zeigen. Ohne Subgrid wird jede Karte als unabhängiges Grid definiert, was bedeutet, dass die Spurengrößen in der ersten Karte nicht auf eine Höhenänderung in der zweiten reagieren können. Aus einem Beispiel, das Rachel Andrew verwendet hat von einem Beispiel, hier ist eine einfache Gruppe von Karten.

Showing three columns of cards where each card has a headers with a dark blue background and white text, content with a white background, and a footer with a dark blue background. The cards are uneven because some of them have more content that others.
Quelle: Rachel Andrew

Subgrid erlaubt es den Karten, die auf dem Elterngrid definierten Zeilen zu verwenden, was bedeutet, dass sie auf Inhalte in umliegenden Karten reagieren können.

The same three columns of cards, but with each card perfectly aligned with the others.
Quelle: Rachel Andrew

Jede Karte in diesem Beispiel nimmt immer noch drei Zeilenspuren ein, aber diese Zeilen sind nun auf dem Elterngrid definiert, wodurch jede Karte den gleichen vertikalen Platz einnehmen kann.

Für das Beispiel, mit dem wir gearbeitet haben, müssen wir keine Zeilen verwenden. Stattdessen müssen wir Spalten basierend auf Inhalten von Geschwister-Grids dimensionieren. Zuerst richten wir das Elterngrid so ein, dass es die beiden <fieldset>-Elemente enthält. Dies ähnelt dem Code, den wir zuvor im auto-fit-Demo betrachtet haben.

.wrapper--accessibility-tools {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  grid-gap: 10px;
}

Dann positionieren wir jedes Subgrid auf dem Elterngrid.

.sub-grid {
  display: grid;
  grid-column: span 3;
  grid-template-columns: subgrid;
  align-items: center;
}
Showing the two groups of bright pink buttons with both groups on the same row and all the buttons have a consistent width.

Alle Labels und Schaltflächen sind nun an den Spuren ihres Elterngrid ausgerichtet und bleiben konsistent. Sie haben jeweils eine gleiche Breite, basierend auf dem verfügbaren Platz. Wenn nicht genügend Platz für jedes verschachtelte Grid auf einer Zeile vorhanden ist, bricht das zweite in eine neue Zeile um.

The two groups of buttons vertically stacked and the buttons are all consistently aligned with the same width.

Diesmal richten sich die beiden verschachtelten Grid-Elemente perfekt aus. Das Grid ist auch flexibel, wenn wir einen längeren Titel auf einer der Schaltflächen einfügen, reagieren die anderen Elemente entsprechend.

Browserkompatibilität

Die Unterstützung für Subgrid ist zum Zeitpunkt des Schreibens nicht großartig. Sie wird nur in Firefox 71+ unterstützt, obwohl es positive Signale von anderen Browsern gibt. CSS-Feature-Queries können verwendet werden, um alternative Stile für Chrome und Edge bereitzustellen.

Diese Browser-Supportdaten stammen von Caniuse, wo weitere Details zu finden sind. Eine Zahl gibt an, dass der Browser die Funktion ab dieser Version unterstützt.

Desktop

ChromeFirefoxIEEdgeSafari
11771Nein11716.0

Mobil / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
12712712716.0

Beachten Sie, dass ich in diesen Demos einen zusätzlichen Wrapper um die Fieldsets verwende. Dies dient zur Behebung eines Fehlers bei Formelementen und Grid und Flexbox.

<fieldset class="accessibility-tools__colour-theme">
  <div class="wrapper"></div>
</fieldset>

Das Layout-CSS wird auf den Wrapper angewendet, wobei das Fieldset auf display: contents gesetzt ist.

.accessibility-tools fieldset {
  display: contents;
  border: 0;
} 

Weitere Lektüre zum Thema