Abschnitt 9 · Lektion 2
Richtung und Umbruch
Vier Karten, jede 180 Pixel breit, stehen in einem Container, der für sie zu schmal ist. Sie brechen nicht in eine zweite Zeile um, sie werden alle schmaler. Das liegt am Umbruch, und um den geht es hier. Vorher kommt aber noch die Richtung dran.
Die Richtung drehen
<p class="titel">row (Standard)</p>
<div class="reihe row">
<div class="kasten">1</div>
<div class="kasten">2</div>
<div class="kasten">3</div>
</div>
<p class="titel">row-reverse</p>
<div class="reihe row-reverse">
<div class="kasten">1</div>
<div class="kasten">2</div>
<div class="kasten">3</div>
</div>
<p class="titel">column</p>
<div class="reihe column">
<div class="kasten">1</div>
<div class="kasten">2</div>
<div class="kasten">3</div>
</div> body {
font-family: system-ui, sans-serif;
}
.titel {
margin-bottom: 4px;
font-size: 14px;
color: #52525b;
}
.reihe {
display: flex;
margin-bottom: 24px;
padding: 8px;
background-color: #f4f4f5;
}
.kasten {
margin: 4px;
padding: 8px 16px;
font-weight: 700;
color: #ffffff;
background-color: #2563eb;
}
/* Im Markup steht überall dieselbe Reihenfolge 1, 2, 3.
Nur die Richtung des Containers ist verschieden. */
.row {
flex-direction: row;
}
.row-reverse {
flex-direction: row-reverse;
}
.column {
flex-direction: column;
} flex-direction kennt vier Werte.
rowlegt die Hauptachse von links nach rechts. Das ist der Standard, du schreibst ihn selten hin.row-reverselegt sie von rechts nach links.columnlegt sie von oben nach unten.column-reverselegt sie von unten nach oben.
Im Beispiel steht im Markup dreimal dieselbe Folge 1, 2, 3. Auf dem Bildschirm sieht sie dreimal anders aus.
Mit jedem Wechsel zwischen Reihe und Spalte tauschen justify-content und align-items ihre Bedeutung. Bei row schiebt justify-content waagerecht, und align-items richtet senkrecht aus. Bei column ist es andersherum. Die Eigenschaften folgen der Achse, nicht der Bildschirmrichtung.
Der Standard heißt nowrap
<p class="titel">flex-wrap: nowrap (Standard)</p>
<div class="reihe ohne">
<div class="karte">Tipptrainer</div>
<div class="karte">Referenz</div>
<div class="karte">Newsletter</div>
<div class="karte">Portfolio</div>
</div>
<p class="titel">flex-wrap: wrap</p>
<div class="reihe mit">
<div class="karte">Tipptrainer</div>
<div class="karte">Referenz</div>
<div class="karte">Newsletter</div>
<div class="karte">Portfolio</div>
</div> *,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: system-ui, sans-serif;
}
.titel {
margin-bottom: 4px;
font-size: 14px;
color: #52525b;
}
.reihe {
display: flex;
margin-bottom: 24px;
padding: 8px;
background-color: #f4f4f5;
}
/* Die Karten sollen 180px breit sein. Oben werden sie
es nicht: der Platz reicht nicht, und statt
umzubrechen geben alle vier nach. */
.karte {
width: 180px;
margin: 4px;
padding: 16px;
color: #ffffff;
background-color: #18181b;
}
.mit {
flex-wrap: wrap;
} Ein Flex-Container bricht seine Items nicht um, solange man es ihm nicht sagt. flex-wrap: nowrap ist der Standardwert, und mit ihm bleiben alle Items in einer Zeile, koste es, was es wolle.
Was es kostet, siehst du im oberen Kasten des Beispiels. Vier Karten mit width: 180px sollen in einen Container, in den sie nicht passen. Statt umzubrechen, geben alle vier nach und werden schmaler. Die Breitenangabe steht da, sie ist gültig, und trotzdem hält sich niemand daran.
Flex-Items haben ein eingebautes flex-shrink: 1 und dürfen also schrumpfen, wenn der Platz nicht reicht. Ausführlich kommt das in 9.6. Wird eine Breite in einem Flex-Container übergangen, frage ich deshalb zuerst, ob dort überhaupt umgebrochen werden darf.
flex-wrap hat drei Werte.
nowraphält alles in einer Zeile, notfalls gequetscht. Das ist der Standard.wrapmacht neue Zeilen auf, sobald der Platz nicht reicht.wrap-reversetut dasselbe, nur entstehen die neuen Zeilen nach oben statt nach unten.
Dazu gibt es das Shorthand flex-flow: row wrap, das Richtung und Umbruch in einer Zeile setzt. Ich schreibe die beiden meistens einzeln hin. Das Shorthand spart dir eine Zeile und kostet dich ein bisschen Lesbarkeit, und am Ende ist das Geschmackssache.
Was row-reverse nicht ändert
<nav class="menue">
<a href="#">Start</a>
<a href="#">Projekte</a>
<a href="#">Kontakt</a>
</nav>
<p class="hinweis">
Auf dem Bildschirm steht Kontakt links. Klick in die Seite und
wander mit der Tabulatortaste durch die Links: die Reihenfolge
ist Start, Projekte, Kontakt. Das Markup hat sich nicht geändert,
nur das Bild davon.
</p> body {
font-family: system-ui, sans-serif;
}
/* row-reverse dreht die Darstellung um. Die
Tastatur und der Screenreader folgen weiter
dem Markup. */
.menue {
display: flex;
flex-direction: row-reverse;
padding: 8px;
background-color: #18181b;
}
.menue a {
margin: 4px 8px;
padding: 4px 8px;
color: #ffffff;
}
.menue a:focus-visible {
outline: 3px solid #60a5fa;
outline-offset: 2px;
}
.hinweis {
max-width: 46ch;
color: #52525b;
} row-reverse und column-reverse ändern nur die Darstellung. Die Reihenfolge im Dokument bleibt, wie sie ist, und daran hängt mehr, als man beim Hinschauen merkt. Die Tabulatortaste wandert in der Markup-Reihenfolge durch die Links. Ein Screenreader liest sie in der Markup-Reihenfolge vor. Navigierst du mit der Tastatur, springst du im Beispiel von rechts nach links durch das Menü, und auf dem Bildschirm ist dafür kein Grund zu sehen.
Wie in Lektion 6.4 kannst du in der Eingabezeile der Console nachfragen, und zwar mit dieser Zeile.
[...document.querySelectorAll(".menue a")].map(a => a.textContent).join(", ")
Die Antwort ist Start, Projekte, Kontakt, in dieser Reihenfolge. Auf dem Bildschirm steht Kontakt aber ganz links. In dieser Reihenfolge kommst du mit der Tabulatortaste durch, und so liest ein Screenreader sie vor.
Für ein Menü, eine Liste von Formularfeldern oder eine Reihenfolge, die inhaltlich etwas bedeutet, ist das ein Fehler. Für rein dekorative Umsortierungen ist es in Ordnung.
Wenn die Reihenfolge wichtig ist, ändere ich deshalb das Markup. CSS ordnet die Darstellung, nicht das Dokument.
order hat denselben Haken
<nav class="menue">
<a href="#">Start</a>
<a href="#">Projekte</a>
<a href="#">Kontakt</a>
</nav>
<p class="hinweis">
Auf dem Bildschirm steht Kontakt vorn, weil er order: -1 hat.
Wander mit der Tabulatortaste durch die Links: die Reihenfolge
ist trotzdem Start, Projekte, Kontakt. Wer sieht, bekommt eine
andere Seite als wer hört oder tippt.
</p> body {
font-family: system-ui, sans-serif;
}
.menue {
display: flex;
gap: 8px;
padding: 8px;
background-color: #18181b;
}
.menue a {
padding: 4px 8px;
color: #ffffff;
}
.menue a:focus-visible {
outline: 3px solid #60a5fa;
outline-offset: 2px;
}
/* Der Standardwert ist 0. Alles Kleinere rutscht
nach vorn, alles Größere nach hinten. Am Markup
ändert sich dabei nichts. */
.menue a:last-child {
order: -1;
}
.hinweis {
max-width: 52ch;
color: #52525b;
} order verschiebt ein Item in der Darstellung. Der Standardwert ist 0, alles Kleinere rutscht nach vorn, alles Größere nach hinten.
Und es hat denselben Haken wie row-reverse, nur schlimmer, weil order gezielt einzelne Elemente umsortiert. Die Tastatur und der Screenreader folgen weiter dem Markup. Wer sieht, bekommt eine andere Reihenfolge als wer hört. Dieselbe Zeile in der Eingabezeile der Console gibt auch hier Start, Projekte, Kontakt zurück, obwohl Kontakt vorn steht. In einer Navigation oder einem Formular ist das ein echter Fehler, kein Schönheitsfehler.
In Ordnung ist es für unkritische Umsortierungen nach Bildschirmgröße, etwa ein dekoratives Bild, das auf dem Handy über den Text rutschen soll.
In der Aufgabe stehen zwei Container, und an beiden steht bisher nur display: flex.
Zum Mitnehmen
flex-direction dreht die Achsen, flex-wrap erlaubt neue Zeilen. Der Standard nowrap quetscht lieber, als umzubrechen, und row-reverse und order drehen nur das Bild, nicht die Reihenfolge für Tastatur und Screenreader.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
Was in dieser Lektion steckt
-
Artikel mit 4 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe im Editor, direkt im Browser geprüft
Öffnet sich mit dem Basis Konto.