Positionierung von Elementen auf Webseiten war immer ein
großes Thema, besonders für Einsteiger ins Webdesign. Aber auch so manch
erfahrener Developer kämpft manchmal mit den Elementen, die so ganz und gar
nicht dorthin wollen, wo er sie haben will – besonders, wenn die ganze Sache
dann auch noch responsiv sein soll.
Glücklicherweise hat CSS dafür ein Ass im Ärmel: die Flexbox. Weil dieses Tool derart mächtig
ist, beschäftigen wir uns auch in unseren Kursen eingehend damit.
Flexible Box Module
Mit vollständigem Namen heißt die Flexbox eigentlich Flexible Box Module. Der Name ist
Programm: Es handelt sich um ein Modul, das uns ermöglicht, flexibel mit Boxen
umzugehen.
Auch vor Flexbox-Zeiten war es natürlich schon möglich,
Elemente nebeneinander anzuordnen, beispielsweise mittels der float-property. Dabei entstehen
allerdings Probleme, die bei falscher Handhabung dazu führen können, dass uns
die Struktur der gesamten Seite zusammenbricht – aber das ist Thema eines
anderen Artikels. Die Flexbox ermöglicht uns das Positionieren von Elementen
ohne die Schwierigkeiten aller früheren Lösungen – und noch Einiges mehr.
Die bisherigen Lösungsansätze funktionierten so, dass man
den inneren Elementen Anweisungen gab, wie sie sich verhalten sollten, also
beispielsweise float: left.
Die Flexbox geht den umgekehrten Weg: Wir sagen dem
Container, wie sich die Elemente, die sich darin befinden, verhalten sollen.
Für unser Beispiel nehmen wir an, unsere Flexbox ist ein Div
mit der Klasse .flex-container, darin
liegen mehrere andere Divs mit der Klasse .flex-item.
Diese flex-items könnten Text,
Bilder, Tabellen oder jeden anderen nur erdenklichen Content enthalten; was wir
dort dann hineinpacken, bleibt jedem selbst überlassen – uns interessiert jetzt
lediglich das Verhalten der Elemente.

Im Bild oben sehen wir das Standardverhalten, wenn wir
mehrere Divs (orange) in einen Container (blau) packen: als Blockelemente
ordnen sie sich untereinander an. Damit unser Container zur Flexbox wird,
bedarf es einer Anweisung:

Ohne weitere Anweisung ordnen sich die flex-items nun nebeneinander in der Flexbox an:

Im ersten Moment sieht es so aus, als würden sie sich nun so
verhalten, als hätte man ihnen die Anweisung float: left
gegeben, aber das stimmt so nicht ganz. Zum einen haben wir hier nicht das
Problem mit dem übergeordneten Container, wie bei float: left;
zum anderen werden die Elemente von der Flexbox erstmal alle in eine Zeile
gestopft, solange wir keine weiteren Anweisungen machen. Und das auch, wenn wir
eigentlich eine fixe Breite für die flex-items
definiert haben.
Hätten wir jetzt nicht drei, sondern zwölf Elemente (zwecks
Demonstration unsinnig viele) in der Flexbox, dann werden die flex-items zusammengequetscht, um alle
in dieser einen Zeile unterbringen zu können:

Die angegebene Breitenangabe wird ignoriert. Damit Elemente,
die nicht mehr in die erste Zeile passen, in die nächste Zeile umspringen
dürfen (wie bei float), müssen wir
das der Flexbox explizit erlauben:

Die entsprechende Anweisung heißt flex-wrap: wrap;
. Damit haben die flex-items wieder
ihre zugewiesene Breite und dürfen in die nächste Zeile umspringen:

Soweit waren wir auch schon vor Flexbox-Zeiten. Das würde
jetzt dem Verhalten eines korrekt angewendeten float: left
entsprechen. Die Flexbox kann aber noch um einiges mehr.
Horizontale Aufteilung: justify-content
Wer schon einmal versucht hat, Elemente mittels text-align: center zu zentrieren, hat schon mindestens eine
mittelschwere Enttäuschung hinter sich. Das funktioniert natürlich nicht bei
Blockelementen. Vielleicht wurde dann mit dem Trick mit margin: 0 auto;
gearbeitet? Ja, das funktioniert, aber die Flexbox kann das besser:

Die Eigenschaft justify-content
ist für die horizontale Anordnung der Elemente in einer Flexbox zuständig.
Dabei gibt es (neben dem Default flex-start,
also am Beginn der Flexbox ausgerichtet) noch drei weitere spannende Angaben. Justify-content: center; zentriert die Elemente horizontal:

Das funktioniert für eine oder mehrere Zeilen.
Ein weiterer praktischer Wert ist justify-content:
space-between:

Dabei versuchen die Elemente, innerhalb einer Zeile so viel Abstand
zueinander zu halten, wie irgend möglich. Das heißt, das erste Element liegt
ganz am Anfang der Flexbox, das letzte ganz am Ende, und der in der Zeile noch
zur Verfügung stehende Platz wird gleichmäßig als Abstand zwischen den
Elementen aufgeteilt. Das „gleichmäßig“ ist hier der entscheidende Punkt: Wir
müssen nicht berechnen: wie breit sind meine Elemente? Wie breit kann ich also
die Abstände dazwischen machen? Wo muss hier ein margin hin? Links? Rechts? Was mache ich mit dem ersten und letzten
Element? All das macht die Flexbox für uns automatisch. Allerdings handelt es
sich bei den Abständen in der Flexbox weder um margin noch padding – die
Abstände ergeben sich aus dem nach Abzug der Breite der flex-items noch zur Verfügung stehenden Platz.
Es gibt noch einen dritten, sehr hilfreichen Wert, justify-content: space-around:

Hierbei wird der nach Abzug der Breite der flex-items noch zur Verfügung stehende
Platz gleichmäßig als Abstand links und rechts von den flex-items aufgeteilt. Daher ist der Abstand zwischen den flex-items doppelt so breit wie der
linke Abstand von flex-item 1 und der
rechte Abstand von flex-item 3;
zwischen flex-item 1 und 2 sowie zwischen 2 und 3 ergibt sich der
Abstand aus dem rechten Abstand des ersten und dem linken Abstand des zweiten
Elements.
Es gibt noch ein paar weitere Werte, die justify-content zugeordnet werden
könnten, aber center, space-around und space-between sind die wichtigsten.
Diese Angaben lassen sich auch problemlos mit einem margin für die flex-items kombinieren; in diesem Fall wäre der margin dann der Mindestabstand, der
eingehalten werden muss.
Selbstverständlich kann auch die Flexbox padding und/oder margin bekommen.
Vertikale Aufteilung: align-items
Bisher hatte unsere Flexbox noch keine Höhenangabe. Das hat
den Vorteil, dass der Container mit dem Inhalt mitwachsen kann. Somit entstehen
auch keine Probleme, wenn Elemente in die nächste Zeile springen, weil der viewport kleiner wird (entweder, weil
jemand mit dem Browserfenster herumspielt oder weil die Seite auf einem
kleineren Ausgabegerät betrachtet wird).
In manchen Fällen werden wir aber einen Container mit
einer fixen Höhe haben wollen. Für unser Beispiel weise ich dem flex-container eine Höhe von 300px zu:

Ohne
weitere Angaben zur Anordnung der Elemente kleben alle erst einmal in der
linken oberen Ecke (also in unserem Fall an flex-start):

Die für die vertikale Aufteilung zuständige Eigenschaft
heißt align-items. Die macht
natürlich auch nur dann Sinn, wenn die Flexbox eine fixe Höhe hat, ansonsten
ist die Flexbox so hoch wie ihr Inhalt und wir haben gar nicht die Möglichkeit,
Elemente vertikal auszurichten.
Mit align-items: flex-end
bringen wir die flex-items nach
unten:

…und mit align-items: center
können wir sie vertikal zentrieren:

Das ist eine enorme Erleichterung im Vergleich zu
vor-Flexbox-Zeiten: da war es noch ein Kampf mit der Materie, wenn man Elemente
vertikal zentrieren wollte, der nicht selten über JavaScript gelöst wurde. Mit
der Flexbox brauchen wir lediglich diese eine Anweisung.
Eine spannende Sache lässt sich mit align-items:
stretch noch erreichen, wenn die flex-items
keine eigene fixe Höhe haben:

Die flex-items
erstecken sich dann über die gesamte Höhe der Flexbox.
Natürlich lassen sich die Anweisungen für die horizontale
und vertikale Ausrichtung miteinander kombinieren:

Mit diesem magischen Zweizeiler erreichen wir eine perfekte Zentrierung unseres Elements/unserer
Elemente innerhalb der Flexbox:

Den gleichen Effekt hätte die Anweisung margin: auto
innerhalb einer Flexbox.
Ausrichtung nach Spalten: flex-direction
Bisher haben wir uns nur um die zeilenweise Anordnung von
Elementen gekümmert. Tatsächlich steckt da ein Default-Setting dahinter,
nämlich flex-direction: row; .
Wenn unsere Flexbox eine Höhenangabe hat, können wir aber
auch für eine Ausrichtung der Elemente in Spalten sorgen:

Beachte, dass mit flex-wrap: wrap das
Umspringen in eine neue Spalte erlaubt werden muss – sonst ordnen sich alle in
einer einzigen Spalte untereinander an! Die Anweisungen oben ergeben folgendes
Bild:

Hier müssen wir natürlich, wie immer bei fix vergebenen
Höhen, aufpassen, dass sich alles innerhalb des Containers ausgeht. Diese flex-items sind 110px hoch, somit passen
zwei wunderbar in eine Spalte eines 300px hohen Containers.
Das sind die wichtigsten Anweisungen, die man braucht, um
eine Flexbox gut strukturieren zu können. Es gibt noch ein paar weitere
Spielereien, die aber etwas seltener vorkommen; so kann man beispielsweise mit flex-direction: row-reverse oder column-reverse
für eine andere Anordnung der Elemente sorgen, als sie im Dokumentfluss
vorliegt.
Mit einer shorthand-property
names flex-flow lassen sich die
Eigenschaften flex-direction und flex-wrap kombinieren:
Beispiel: flex-flow: row wrap;
Anweisungen an Elemente in der Flexbox
Auch den Elementen innerhalb der Flexbox kann man noch ein
paar bestimmte Anweisungen geben; allerdings wird man das in der Praxis nicht
allzu häufig brauchen. Daher hier nur ein paar kurze Tipps, was man denn noch
so alles mit der Flexbox anstellen kann.
Im Normalfall ordnen sich die Elemente in der Reihenfolge
an, wie sie auch im Dokumentfluss vorkommen, und in den meisten Fällen wollen
wir das auch so. Es hat ja schließlich seinen Grund, warum wir sie so
angeordnet haben.
Diese Reihenfolge lässt sich aber auch über CSS verändern.
Bleiben wir beim schon verwendeten Beispiel von eben (die Elemente sind in
Spalten angeordnet), aber die sechs Elemente in der Flexbox bekommen jetzt
jedes auch noch eine Id (#no1 – 6). Über die Id können wir jetzt jedes Element
gesondert ansprechen und ihm eine andere Position in der Reihenfolge zuweisen
(das wäre übrigens auch über .flex-item:nth-child(x)
möglich, wenn wir uns die IDs sparen wollen):



Jedem dieser Elemente wurde mittels order eine neue Position zugewiesen (z.B. order: 2).
Dabei zu beachten: gezählt wird wie in einem Array beginnend mit der Stelle 0!
Das flex-item 5 befindet sich also an
der Stelle 0 (order: 0;), das flex-item 4 an der Stelle 5 (order: 5;).
Das funktioniert genauso für eine Ausrichtung in Zeilen (flex-direction: row; bzw. Defaultwert):

Wenn die flex-items
keine fixe Breite haben, sondern sich gleichmäßig über die Zeile ausbreiten
sollen, kann man auch noch bestimmen, in welchem Verhältnis sie sich ausbreiten
(oder schrumpfen) dürfen. Dafür gibt es die Eigenschaften flex-grow und flex-shrink.
Flex-grow bedeutet, dass ein Element,
dem flex-grow: 3; vergeben wurde, sich dreimal so
breit machen darf wie die anderen, die ein flex-grow: 1;
erhalten haben:

Mit flex-shrink
verhält es sich umgekehrt: Es bestimmt, in welchem Verhältnis zueinander
Elemente schrumpfen sollen, wenn es sich in der Zeile nicht mehr ausgeht.
Dafür gibt es auch noch eine shorthand-property: Mit flex:
können wir flex-grow und flex-shrink zusammenfassen. Der Default
ist flex: 0 1; .
Viel Spaß beim Herumprobieren! Und vielleicht sehen wir uns
ja in einem ppedv-Kurs zum Thema HTML und CSS!