Mit Flex Direction und Grow Inhalte ganz unten positionieren
Beitrag vom
Wie man Inhalte in einem Container am unteren Rand platziert ist ja eigentlich schon alte Schule: Der Container wird relativ positioniert und das unten zu platzierende Element wird absolut positioniert. Ein kurzes bottom: 0; et voilà: Das Ding klebt am Fuße des Containers.
Solange wir den Container groß genug aufblähen, klappt das auch ganz gut. Wenn der Inhalt aber variabel ist, können wir uns nicht mehr auf Größenangaben in Höhe oder Padding verlassen. Irgendwann sitzt der absolut positionierte Block wieder da, wo er nicht hin gehört.
Ich weiß ich weiß, ich habe neulich schon einmal über die Vorzüge des Flexbox-Modells geschwärmt und einen Artikel dazu geschrieben. Hier ging es darum, wie man Inhalte gleichmäßig und ohne Javascript auf dem verfügbaren Platz aufteilt. Das Ganze basiert auf der Eigenschaft, dass Flexboxen den ganzen verfügbaren Platz in der Höhe einnehmen. Das Ursprüngliche DOM sah so aus:
<div class="container">
<div class="box">
<div class="content">
<h3>Headline</h3>
<p><img src="http://www.placecage.com/c/600/600"></p>
<p>Donec gravida posuere arcu.</p>
<a href="#">Mehr erfahren</a>
</div>
</div>
...
</div>
Der .container wurde auf display: flex; gesetzt, damit die Boxen schön nebeneinander fließen. Damit der Inhalt noch schön auf gleiche höhe gezogen wird, bekommt auch gleich noch die .box ein display: flex;. Da alles in der Box noch untereinander bleiben soll, wurde der Inhalt in ein weiteres DIV gepackt und die Sache war gegessen.
Jetzt möchte ich aber, dass der Call to Action Link innerhalb der Box ganz unten ist. Da die Höhe der Boxen variabel ist, bringt’s die absolute Positionierung hier auch nicht mehr. Es ist also an der Zeit, noch mal in die Flex-Trickkiste zu greifen:
Wir erinnern uns, dass Flex versucht, die Kindelemente auf den verfügbaren Platz nebeneinander zu platzieren. Das passiert standardmäßig in der Horizontalen, bei aktiviertem Flex Wrap bricht bei Bedarf die Zeile um. Was nebeneinander schon ganz gut aussieht, hätte ich jetzt gerne vertikal. Das machen wir, indem wir flex-direction: column; setzen. Flex-Kinder werden jetzt untereinander platziert.
Normalerweise wird die Größe eines Flex-Kindes durch den Inhalt bestimmt – ähnlich wie bei fließenden oder positionierten Elementen. Flex Grow erlaubt es, ein oder mehrere Kind-Elemente wachsen zu lassen, wenn noch Platz im Container über ist. Das Verhältnis der Aufteilung wird mit flex-grow: n; proportional festgelegt. Die Angabe ist dabei ein Vielfaches von 1 und bestimmt das Verhältnis der Aufteilung des Freiraums zwischen allen beteiligten Elementen.
Wenn alle Kinder den gleichen Flex-Grow Wert besitzen, wird der Weißraum der Box auf alle Kinder gleichmäßig verteilt. Hat ein Element einen doppelt so hohen Wert, wird ihm auch doppelt so viel freier Platz gut geschrieben.
Nehmen wir an, wir haben 4 Kinder in einer Flexbox. Die ersten Beiden bekommen ein flex-grow: 1; und das Dritte bekommt flex-grow: 2;. Das vierte Kind bekommt gar kein Flex Grow.
Der Browser nimmt zunächst die Größe des Containers und zieht davon die native Größe der Kinder ab. Übrig bleibt der Freiraum. Dieser Freiraum wird dann anhand der Flex-Grow Proportion auf alle Kinder verteilt, die Grow nutzen.
Wir haben also insgesamt 2x eine Einheit und 1x zwei Einheiten. Den Freiraum (und nicht die komplette Container Breite) teilen wir also durch 4 und geben Kind 1 und 2 jeweils ein Viertel und Kind 3 zwei Viertel, sprich die Hälfte des verfügbaren Platzes. Kind 4 bleibt bei seiner nativen Größe, da es kein Flex Grow nutzt.
Im DOM finden wir unsere Inhalte in einem DIV mit der Klasse „content“. Da das Elternelement schon eine Flexbox ist, wird für den content-Container schon der gesamte Platz zur Verfügung gestellt. Die Inhalte reihen sich ganz normal von oben nach unten ein. Wir haben also noch Freiraum übrig.
Unser Ziel ist es jetzt, den Inhalt oberhalb des Links so weit aufzublähen, dass der gesamte Freiraum belegt wird, damit unser Link ganz ans Ende gedrückt wird.
Also verwandeln wir unser content-DIV in eine Flexbox und bewegen es via flex-direction: column; dazu, alles untereinander stehen zu lassen.
Um den freien Weißraum jetzt noch zu füllen, müssen wir dem vorletzen Kindelement ein flex-grow: 1; verpassen.
Ich gehe hier wieder von dynamischen Inhalten aus und weiß nicht, was das letzte Element sein wird. Es direkt anzusprechen ist mir deshalb nicht möglich. Also packe ich einfach alles oberhalb des Links in ein weiteres DIV und lasse es wachsen:
<div class="container">
<div class="box">
<div class="content">
<div>
<h3>Headline</h3>
<p><img src="http://www.placecage.com/c/600/600"></p>
<p>Donec gravida posuere arcu.</p>
</div>
<a href="#">Mehr erfahren</a>
</div>
</div>
...
</div>
.content{
display: flex;
flex-direction: column;
}
.content>div{
flex-grow: 1;
}
Wenn man Flex-Grow verstanden hat, ist diese Aufgabe prinzipiell gar nicht mal so schwierig: Flexbox aufspannen, ein Kind wachsen lassen. Fertig.
Es gibt neben Flex Grow noch die Eigenschaften für Shrink und Base. Hiermit kann man die Nutzung des Weißraums noch weiter beeinflussen. Das soll jetzt aber nicht Bestandteil dieses Artikels sein. Wer sich generell über das Flexbox-Modell interessiert, finder auf css-Tricks eine sehr schöne Zusammenfassung aller Eigenschaften.
Zum Rumfuddeln hier noch ein Codepen mit dem Ergebnis:
See the Pen Flex Bottom by Kai Brockelt (@donkaisen) on CodePen.