Inhalt
- 1. Warum ich Flexbox-Fan bin?
-
2. Der Eltern-Container: Die Basics
- 2.1 display: Flexbox ön oder öff
- 2.2 flex-direction: Zeile oder Spalte?
- 2.3 flex-wrap: "Zeilenumbruch" gefällig?
- 2.2 / 2.3 flex-flow: Kurzschreibweise
- 2.4 justify-content: Horizontale Ausrichtung
- 2.5 align-items: Vertikale Ausrichtung
- 2.6 align-content: Zeilenabstand bei mehrzeiligen "Kindergruppen"
- 3. Kind-Elemente: Positionieren und ausrichten
- 4. Anwendungsbeispiele
1. Warum ich Flexbox-Fan bin?
Vorkonfektionierte Frameworks wie das Responsive Grid System, xy.css, pure.css, Bootstrap oder UIkit haben sicher ihre Vorteile, sind aber in der Nutzung nicht immer supereinfach, Außerdem bin ich – und der/die ein oder andere Leser/in – immer daran interessiert, alles (1) "from scratch" und (2) ganz alleine selber zu machen. Und von Grund auf verstehen, was da eigentlich passiert – oder daran verzweifeln und am Ende doch zu einem Framework von der Stange greifen 🙂
Für den Hobbyschrauber bietet CSS3 das Flexbox-Modul (mit vollem Namen CSS Flexible Box Layout Module, Modul = Gruppe von CSS-Eigenschaften rund um display: flex;
): Damit können in einem Container-Elternelement mehrere Kind-Elemente flexibel in Reihen und/oder Spalten angeordnet werden, auch wenn Ihre Ausmaße und Inhalte unbekannt, variabel oder einfach krass unterschiedlich sind. Kompatibilität:
- Firefox: Seit v.28 ohne Prefix
- Chrome: Seit v.29 ohne Prefix
- Opera: Seit v.17 ohne Prefix
- Safari: Seit v.9 ohne Prefix
- Edge: Seit v.12 ohne Prefix
- Internet Explorer: v10 teilweise (mit Präfix -ms-), ab v11 ohne Präfix, allerdings nicht vollständig
- Mobile Safari: Seit iOS 9.2 ohne Prefix
- Android Browse: Seit Android 4.4 ohne Prefix
vgl. caniuse.com & shoudiprefix.com.
Die Kompatibilität steht dem Einsatz also nicht im Wege, und das Flexbox-Modul lässt sich recht einfach für responsive, auch komplexe und verschachtelte Seitenlayouts nutzen. Mittlerweile nutze ich Flexbox inflationär.
Zum Beispiel lassen sich Probleme wie "Gleiche Höhe von floatenden oder inline Divs mit unterschiedlichem Inhalt" oder ähnliche Fragen mit Flexbox schick beantworten: Die Berechnung und Verteilung von Boxen innerhalb des Elterncontainers übernimmt der Brower. Schönen Dank dafür!
Umsetzung mit einer ul
, li
’s mit display:inline
(bzw. inline-block
):
- Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt.
- Franz jagt im komplett verwahrlosten Taxi quer durch Bayern.
Vogel Quax zwickt Johnys Pferd Bim. - Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich.
Umsetzung mit div
’s, alle mit float:left;
:
Umsetzung mit display:flex;
:
Vogel Quax zwickt Johnys Pferd Bim.
Die ersten beiden Umsetzungen sind bei variablem bzw. dynamischem Inhalt der Kind-Elemente einigermaßen unschön, wirken zumindest unaufgeräumt. Ein Workaround wäre, z.B. via jquery (hier oder hier) die Höhe des höchsten Kindes zu ermitteln und als Köhe der anderen zu setzen. Das geht aber mittels "flexboxing" deutlich einfacher – und ohne js-/jQuery-Kenntnisse 🙂
Fangen wir mit den Grundbegriffen an: Innerhalb eines Containers (Eltern-Element) können Items (Kind-Elemente) in verschiedener Richtung (spaltenweise, zeilenweise) nach unterschiedlichen Regeln zu Anordnung, Größe, Position angeordnet werden:
So weit, so einfach. Und nun: Schauen wir uns das Flexbox-Modul im Detail an.
Innerhalb des Flexbox-Moduls stehen elf Eigenschaften zur Verfügung:
display
schaltet das Flexbox-Modul an oder aus,flex-direction
legt die Hauptachse (Zeilen- oder Spaltendesign) fest, undflex-wrap
regelt Zeilen- oder Spaltenumbrüche.
Dann kann die gesamte "Kindergruppe" mit Hilfe von
justify-content
(Ausrichtung entlang der Hauptachse), mitalign-items
(Position auf der Sekundärachse) undalign-content
(Ausrichtung entlang der Sekundärachse)
beeinflusst werden. Die einzelnen Kinder können via
flex-basis
("Wunschbreite" vorgeben),flex-grow
(Proportionen vergrößern),flex-shrink
(Proportionen verkleinern),order
(manuelle Sortierung) undalign-self
(Vertikale Ausrichtungalign-content
ür einzelne Kinder überschreiben)
manipuliert werden. Da das so noch sehr theoretisch daherkommt, hier die Beispiele:
2. Der Eltern-Container: Die Basics
2.1 display: Flexbox ön oder öff
Neben den Standards wie block, inline und den table-Werten wird mit CSS3 für das Flexbox-Modul ein neuer Wert für die display
-Eigenschaft eingeführt, welcher das Modul an-. bzw. ausschaltet:
#flexcontainer { display: flex; }
So weit, so einfach.
2.2 flex-direction: Zeile oder Spalte?
Die nächste Eigenschaft ist die Richtung der Kinder-Elemente, wobei row
die Kinder zeilenweise, column
dagegen als Spalte darstellt – klar, oder?
#flexcontainer { flex-direction: row | column; }
Eltern-Container mit display:flex;
+ flex-direction: row;
:
Eltern-Container mit display:flex;
+ flex-direction: column;
:
2.3 flex-wrap: "Zeilenumbruch" gefällig?
Wenn flex-direction:row;
, kann man definieren, ob die "Reihe der Kinder" umgebrochen werden soll oder nicht. Dabei ist zu beachten, dass Teile weiterer CSS-Definitionen (z.B. die Breite der Kinder) ignoriert werden, wenn das Flexbox-Modul versucht, die Kinder gleichmäßig anzuordnen:
#flexcontainer { flex-wrap: nowrap | wrap | wrap-reverse; }
Eltern-Container mit flex-wrap:nowrap;
. Die Breite der Kinder (hier: 20%) wird ignoriert, um sie alle in eine Reihe zu bekommen:
Eltern-Container mit flex-wrap:wrap;
. Die Breite der Kinder wird korrekt interpretiert und die Zeile umgebrochen:
Eltern-Container mit flex-wrap:wrap-reverse;
. Die Breite der Kinder wird korrekt interpretiert, die Zeilen werden von unten nach oben, je von links nach rechts befüllt:
2.2 / 2.3 flex-flow: Kurzschreibweise
Für die beiden vorhergegangenen Definitionen gibt es eine Kurzschreibweise:
#flexcontainer { flex-flow: [flex-direction-Wert] [flex-wrap-Wert]; }
also z.B. flex-flow: row nowrap;
(Standard) oder flex-flow: row wrap;
.
2.4 justify-content: Horizontale Ausrichtung
Soll die "Kindergruppe" links-, rechtsbündig oder zentriert ausgerichtet werden oder gleichmäßig verteilt werden? flex-start
meint links-, flex-end
dagegen rechtsbündig. center
beachtet margin
-Angaben der Kinder und zentriert die gesamte Kinder-Gruppe, space-between
und space-around
ignorieren margin
s der Kinder.
Für responsive Grid-Designs sind space-between
und space-around
"Gold wert": Erstere Einstellung setzt das erste Kind links- und das letzte Kind rechtsbündig und verteilt alle dazwischenliegenden Kinder gleichmäßig. Zweitere verteilt alle Kinder gleichmäßig über den zu verfügung gestellten Platz.
#flexcontainer { justify-content: flex-start | flex-end | center | space-between | space-around; }
Eltern-Container mit justify-content: flex-start;
:
Eltern-Container mit justify-content: flex-end;
:
Eltern-Container mit justify-content: center;
:
Eltern-Container mit justify-content: space-between;
:
Eltern-Container mit justify-content: space-around;
:
Eltern-Container mit justify-content: space-between;
und flex-wrap:wrap;
:
Eltern-Container mit justify-content: space-around;
und flex-wrap:wrap;
:
Das Handling der "Waisen" (also der Kinder aus der letzten Reihe, wenn diese Reihe nicht komplett ist) wird weiter unten noch behandelt.
2.5 align-items: Vertikale Ausrichtung
Soll die Kindergruppe innerhalb des Elterncontainers oben oder unten, mittig oder gedehnt dargestellt werden? Vor allem die Möglichkeit stretch
ist ziemlich cool und macht diverse CSS- Workarounds für gleiche Höhe nebeneinander angeordneter Elemente überflüssig.
#flexcontainer { align-items: flex-start | flex-end | center | baseline | stretch; }
align-items
führt nur dann zu sichtbaren Ergebnissen, wenn der Eltern-Container vertikal auch genügend Platz einräumt. Daher hat der Container hier eine min-height
.
Eltern-Container mit align-items: flex-start;
:
mehr Inhalt
Eltern-Container mit align-items: flex-end;
:
mehr Inhalt
Eltern-Container mit align-items: center;
:
mehr Inhalt
Eltern-Container mit align-items: baseline;
:
Die verschiedenen Schriftgrößen und die eingezeichnete "Baseline" dient lediglich Visualisierungszwecken: Die Baseline ist also die Grundlinie des Textinhalts 🙂
mehr Inhalt
Eltern-Container mit align-items: stretch;
:
mehr Inhalt
2.6 align-content: Zeilenabstand bei mehrzeiligen "Kindergruppen"
Bei flex-wrap: wrap;
und entsprechendem Umbruch der Kind-Elemente kann man mit align-content
beeinflussen, wie die weiteren Zeilen angeordnet werden sollen. Zur Vereinfachung nenne ich diese Einstellung "Zeilenabstand".
#flexcontainer { align-content: flex-start | flex-end | center | space-between | space-around | stretch; }
Auch hier ist mein Lieblingswert stretch
. Vor allem für "responsive Kacheldesigns" in Verbindung mit justify-content: space-between
und align-items: stretch
wird einem da eine Menge Pixelschubserei abgenommen 🙂
align-content
führt nur dann zu sichtbaren Ergebnissen, wenn der Eltern-Container vertikal auch genügend Platz einräumt. Daher hat der Container hier eine min-height
.
Eltern-Container mit align-content: flex-start;
:
Eltern-Container mit align-content: flex-end;
:
Eltern-Container mit align-content: center;
:
Eltern-Container mit align-content: space-between;
:
Eltern-Container mit align-content: space-around;
:
Eltern-Container mit align-content: stretch;
:
3. Kind-Elemente: Positionieren und ausrichten
Kind-Elemente können darüber hinaus bzgl. ("Wunsch-") Breite, Proportion, Sortierung und vertikaler Ausrichtung gestaltet werden.
3.1 flex-basis ("Wunschgröße" vorgeben)
Mit der Angabe eines flex-basis
-Wertes wird eine Breite bzw. Höhe der Kind-Elemente definiert (je nachdem, ob die flex-direction
des Elternelementes row
(dann: Breite) oder column
(dann: Höhe) ist). Die Angabe kann in %, px, em, aber auch als auto
angegeben werden. Der Standard ist auto
:
#flexitem { flex-basis: <px, %, em> | auto; }
3.2 flex-grow & flex-shrink (Proportionen vergrößern oder verkleinern)
Die flex-basis
-Angabe ist allerdings beeinflussbar, indem ein flex-grow
– bzw. flex-shrink
-Wert angegeben wird. Diese beeinflussen die gleichmäßige Verteilung der Kind-Elemente um einen entsprechenden Faktor:
Wenn bei einem Elterncontainer mit flex-direction:row;
die Kinder einen zu geringen basis
-Wert haben, kann mit einem grow
-Wert > 0 (Standard ist 0) der freie Platz aufgeteilt werden: Zum Beispiel würde ein Eltern-Container mit width:100%;
von drei Kinder mit flex-basis: 20%;
nicht ausgefüllt werden, da ja bekanntlich 3 * 20% lediglich 60% ergibt. Der noch zur Verfügung stehende Platz kann dann auf Kinder mit einem flex-grow
-Wert > 0 proportional zu diesen Werten aufgeteilt werden.
Gleiches funktioniert mit dem "Schrumpf"-Wert shrink
. Hier wird das entsprechende Kind im Verhältnis verkleinert, wenn die summierten basis
-Werte alle Kinder zusammmen den horizontal zur Verfügung stehenden Platz des Eltern-Elements überschreiten.
#flexitem { flex-grow: <px, %, em>; flex-shrink: <px, %, em>; }
3.1 / 3.2 flex: Kurzschreibweise
Für die drei obigen Werte gibt es eine Kurzschreibweise nach dem Strickmuster
#flexitem { flex: [flex-grow-Wert] [flex-shrink-Wert] [flex-basis-Wert]; }
Der Standardwert ist 0 1 auto
.
Drei Kinder mit flex-basis:20%;
haben genügend Platz im Elterncontainer, …
shrink:1
basis: 20%
shrink:1
basis: 20%
shrink:1
basis: 20%
… der übrige Platz kann durch ein Kind mit flex-grow:1;
eingenommen werden:
shrink: 1
basis: 20%
shrink: 1
basis: 20%
shrink: 1
basis: 20%
Drei Kinder mit flex-basis:50%;
haben zu wenig Platz im Elterncontainer (mit flex-wrap:nowrap;
), das erste macht via flex-shrink:3;
Platz.
shrink: 3
basis: 50%
shrink: 1
basis: 50%
shrink: 1
basis: 50%
Das ist zu Beginn ein wenig kompliziert, vor allem wenn man mehr als ein Kind mit "Sonderregel zum Platzverbrauch" hat. In Flexboxes, deren Eltern-Container mit flex-box:wrap;
und justify-content:flex-start;
einen Zeilenumbruch beinhalten, kann flex-grow
aber gut dazu genutzt werden, die letzte Reihe ("Waisen") aufzufüllen:
Für alle Kinder im folgenden Beispiel gilt jeweils margin:1%;
, padding:1%
und flex-basis:21%;
. Sie sind also exakt 25% breit (Kleine Erinnerung an das CSS-Box-Model, margin und padding auf beiden Seiten und so…). Die letzte Reihe wird dann mittels einer flex-grow:1;
-Angabe für das :last-child
aufgefüllt.
Mit den vier 25%-Kindern hab ich es mir recht leicht gemacht; das "Waisen"-Problem kann deutlich schwerer zu lösen sein. Interessante Experimente zur "Waisen"-Thematik s. auch hier ("Waisen" mit flex-grow
vergrößern) und hier (Anordnung von "Waisen" in space-between
-Containern).
3.3 order (Manuelle Sortierung)
Mit der order
-Angabe kann die Standard-Reihenfolge der Kinder manipuliert werden. Normalerweise werden die Elemente in der Reihenfolge gerendert, in der sie im Code stehen. Spezielle order
-Angaben je item können das beeinflussen:
#flexitem { order: <nummer>; }
Das dritte Kind (.nth-child(3)
) rückt zwei Felder vor, das sechste (.nth-child(6)
) eins nach hinten:
:nth-child(3) { order: -2 }
:nth-child(6) { order: 1; }
3.4 align-self (Vertikale Ausrichtung für einzelne Kinder überschreiben)
Mit der align-self
-Angabe einzelner Kind-Elemente kann die eigentlich für alle Kinder geltende align-items
-Angabe des Elterncontainers überschrieben werden, z.B.:
#flexcontainer { align-items: flex-start; } #flexitem { align-self: flex-end; }
Zulässige Werte sind flex-start
, flex-end
, center
, baseline
und stretch
.
Das dritte Kind wird via flex-end
ans untere Ende des Eltern-Containers (align-items:flex-start;
) gerückt:
.nth-child(3)
{ align-self:flex-end; }
4. Anwendungsbeispiele
Den bereits hier mit einem CSS-Wokaround umgesetzten "Sticky Footer" kann man deutlich einfacher mit dem Flexbox-Modul umsetzen. Dafür werden in einem Flexcontainer mit flex-direction: column;
Header, Content und Footer untereinander angeordnet und der Content-Block via flex: 1 1 auto;
so weit ausgedehnt wie möglich:
Mir nutzt das Flexbox-Modul besonders bei der Gestaltung von resposiven Rasterlayouts. Je nach Viewport werden unterschiedlich viele Spalten bzw. Elemente je Reihe angezeigt. Im Beispiel kann man sehen, wie unterschiedlich viele Kind-Elemente je Elterncontainer bei gleicher CSS-Definition auf die Verkleinerung des Viewports reagieren. Einfach mal den Browser "schmaler schieben" (Tablet / Smartphone? Wechsel von Portrait zu Landscape):
Dabei fällt auf, dass unterschiedlich viele Elemente (hier 2 Kinder in Reihe 1, 3 Kinder in Reihe 2 und 4 Kinder in Reihe 4) zu einem eventuell unerwünschten Effekt führen: Wenn das letzte Kind einer Reihe umgebrochen wird, wird es gerne mit 100% Breite dargestellt, so dass manchmal drei Kinder in einer und das vierte Kind dreimal so breit in einer neuen Reihe stehen. Dagegen könnte man die Reihen in zwei Teile aufteilen und diese nebeneinander floaten, via Media Queries bei bestimmten Viewportbreiten dann aber wieder anders anordnen:
Und wenn man die Beispiele von oben (Flexbox-Spalten für Header, Content, Footer + Flexbox-Reihen für Content-Boxen incl. Media Queries) kombiniert, erhält man ein komplettes Seitenlayout 🙂