`flex-grow` ist seltsam. Oder?

Avatar of Manuel Matuzovic
Manuel Matuzoc am

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

Das Folgende ist ein Gastbeitrag von Manuel Matuzovic. Er veranschaulicht, wie flex-grow funktioniert, mit all seinen seltsamen Eigenheiten. Dann geht er auf verschiedene Beispiele ein, wie gängige Layoutmuster mit flex-grow und flex-basis implementiert werden können.

Als ich von flex-grow erfuhr, erstellte ich ein einfaches Demo, um herauszufinden, was es tat und wie es funktionierte.
Ich dachte, ich hätte alles verstanden, aber als ich es auf einer Website ausprobierte, die ein Kollege kürzlich erstellt hatte, funktionierte nichts wie erwartet. Egal was wir taten, das Layout sah nicht so aus und funktionierte nicht wie in meinem Demo. Das brachte mich zum Nachdenken und ich begann zu zweifeln, ob ich wusste, worum es bei flex-grow ging.

Wie flex-grow nicht funktioniert

Bevor wir uns eingehend mit der Funktionalität von flex-grow beschäftigen, möchte ich Ihnen erklären, was ich anfangs falsch verstanden habe.

Ich dachte, alle Flex-Items mit flex-grow auf 1 gesetzt hätten die gleiche Breite. Wenn eines der Elemente flex-grow auf 2 gesetzt hätte, wäre dieses Element doppelt so groß wie alle anderen.

Das klingt gut. Es scheint, als ob das genau das ist, was in dem Pen, den ich erwähnt habe, passiert. Das Elternelement ist 900 Pixel breit, der Abschnitt mit flex-grow: 2 hat eine berechnete Breite von 600 Pixeln und das Aside-Element mit flex-grow: 1 hat eine berechnete Breite von 300 Pixeln.

Wie Sie sehen können, funktioniert alles perfekt in diesem Demo, aber es funktionierte überhaupt nicht in einem realen Beispiel, obwohl wir genau die gleiche CSS verwendet haben. Wie sich herausstellt, war das Problem nicht die CSS, sondern der Inhalt (oder der Mangel an Inhalt). Das von mir erstellte Demo funktioniert, weil ich durch die Verwendung von nur zwei leeren Elementen einen Testfall erstellt habe, der zu einfach war, um die wichtigen Besonderheiten der Eigenschaft darzustellen.

Wie flex-grow wirklich funktioniert

Ich habe gerade beschrieben, wie flex-grow nicht funktioniert, aber ich habe Ihnen ein Demo gezeigt, das tatsächlich tut, was ich behaupte, dass es nicht tut (Später in diesem Artikel werde ich den Grund dafür erklären).

Um die Dinge zu klären, lassen Sie mich Ihnen einen weiteren Pen zeigen. Wir haben genau die gleiche Einrichtung wie im ersten Pen, aber diesmal sind die Abschnitts- und Aside-Elemente nicht leer. Jetzt ist das Verhältnis nicht mehr 2:1 und das Element mit flex-grow auf 1 ist tatsächlich größer als das Element mit flex-grow auf 2.

Erklärung

Wenn wir display: flex; auf das Elternelement anwenden und nichts weiter ändern, werden die Kindelemente horizontal gestapelt, egal was passiert. Wenn nicht genug Platz vorhanden ist, schrumpfen sie. Wenn andererseits mehr als genug Platz vorhanden ist, wachsen sie nicht, weil Flexbox von uns möchte, dass wir definieren, wie viel sie wachsen sollen. Anstatt dem Browser mitzuteilen, wie breit ein Element sein soll, bestimmt flex-grow, wie der verbleibende Platz unter den Flex-Items verteilt wird und wie groß der Anteil ist, den jedes Item erhält.

Oder anders ausgedrückt

Ein Flex-Container verteilt freien Platz proportional zu seinen Flex-Grow-Faktoren an seine Items, um die Container zu füllen, oder schrumpft sie proportional zu ihren Flex-Shrink-Faktoren, um Überläufe zu verhindern.

https://drafts.csswg.org/css-flexbox/#flexibility

Demonstration

Das Konzept ist viel einfacher zu verstehen, wenn wir es visualisieren.

Zuerst setzen wir die display-Eigenschaft unseres Elternelements auf flex und dadurch werden unsere Kindelemente zu Flex-Items und werden horizontal nebeneinander positioniert.

Als Nächstes entscheiden wir, wie viele Anteile des zusätzlichen Platzes jedes Element erhält. In unserem vorherigen Beispiel erhält das erste Element 2/3 des verbleibenden Platzes (flex-grow: 2) und das zweite Element 1/3 (flex-grow: 1). Wenn wir wissen, wie viele flex-grow-Werte wir insgesamt haben, wissen wir, durch welche Zahl der verbleibende Platz geteilt werden muss.

Zuletzt haben wir die Anzahl der verteilbaren Stücke. Jedes Element erhält die entsprechende Anzahl von Stücken basierend auf seinem flex-grow-Wert.

Berechnung

Theorie und visuelle Darstellungen sind schön, aber lassen Sie uns ins Detail gehen und die Mathematik für das obige Beispiel durchführen.

Für unsere Berechnung benötigen wir 4 Zahlen: Die Breite des Elternelements, die Anfangsbreite unseres Abschnitts und unseres Aside-Elements und die Gesamtzahl der flex-grow-Werte, die wir verwenden werden.

Elternbreite: 900px
Abschnittsbreite: 99px
Aside-Breite: 623px
Gesamte flex-grow-Werte: 3

1. Zuerst müssen wir den verbleibenden Platz berechnen

Das ist ziemlich einfach. Wir nehmen die Breite des Elternelements und ziehen die gesamte Anfangsbreite jedes Kindelements ab.

900 - 99 - 623 = 178

Elternbreite – Anfangsbreite des Abschnitts – Anfangsbreite des Asides = Verbleibender Platz

2. Als Nächstes müssen wir bestimmen, wie viel ein flex-grow ist

Jetzt, da wir den verbleibenden Platz haben, müssen wir bestimmen, in wie viele Teile wir ihn schneiden wollen. Wichtig ist hier, dass wir den verbleibenden Platz nicht durch die Anzahl der Elemente teilen, sondern durch die Gesamtzahl der flex-grow-Werte. In unserem Fall sind das 3 (flex-grow: 2 + flex-grow: 1)

178 / 3 = 59.33

Verbleibender Platz / Gesamte flex-grow-Werte = "Ein flex-grow"

3. Schließlich wird der zerteilte verbleibende Platz zwischen allen Elementen verteilt

Basierend auf ihren flex-grow-Werten erhält der Abschnitt 2 Stücke (2 * 59,33) und der Aside 1 (1 * 59,33). Diese Zahlen werden zur Anfangsbreite jedes Elements addiert.

99 + (2 * 59.33) = 217.66 (≈218px)

Anfangsbreite des Abschnitts + (flex-grow-Wert des Abschnitts * "Ein flex-grow") = Neue Breite

und

623 + (1 * 59.33) = 682.33 (≈682px)

Anfangsbreite des Asides + (flex-grow-Wert des Asides * "Ein flex-grow") = Neue Breite

Kinderleicht, oder?

Okay, aber warum funktioniert das erste Demo?

Wir haben die Formel, nun finden wir heraus, warum wir tatsächlich die Zahlen bekommen haben, die wir in dem ersten Pen wollten, obwohl wir nicht wussten, was wir taten.

Elternbreite: 900px
Abschnittsbreite: 0px
Aside-Breite: 0px
Gesamte flex-grow-Werte: 3

1. Berechnen Sie den verbleibenden Platz

900 - 0 - 0 = 900

2. Bestimmen Sie, wie viel ein flex-grow ist

900 / 3 = 300

3. Verteilen Sie den zerteilten verbleibenden Platz

0 + (2 * 300) = 600  
0 + (1 * 300) = 300

Wenn die Breite jedes Elements 0 ist, entspricht der verbleibende Platz der tatsächlichen Breite des Elternelements und daher sieht es so aus, als ob flex-grow die Breite des Elternelements in proportionale Teile teilt.

flex-grow und flex-basis

Nur eine kurze Zusammenfassung: flex-grow nimmt den verbleibenden Platz und teilt ihn durch die Gesamtmenge der flex-grow-Werte. Der resultierende Quotient wird mit dem jeweiligen flex-grow-Wert multipliziert und das Ergebnis wird zur Anfangsbreite jedes Kindelements addiert.

Aber was, wenn kein Platz mehr übrig ist oder was, wenn wir uns nicht auf die Anfangsbreite der Elemente verlassen wollen, sondern auf einen von uns gesetzten Wert? Können wir flex-grow immer noch verwenden?

Natürlich können wir das. Es gibt eine Eigenschaft namens flex-basis, die die anfängliche Größe eines Elements definiert. Wenn Sie flex-basis zusammen mit flex-grow verwenden, ändert sich die Art und Weise, wie die Breiten berechnet werden.

<‘flex-basis’> Diese Komponente setzt die Langform flex-basis und definiert die Flex-Basis: die anfängliche Hauptgröße des Flex-Items, bevor der freie Platz gemäß den Flex-Faktoren verteilt wird.

https://drafts.csswg.org/css-flexbox/#valdef-flex-flex-basis

Der große Unterschied, wenn wir flex-basis auf ein Element anwenden, ist, dass wir seine Anfangsbreite nicht mehr in unserer Berechnung verwenden, sondern den Wert seiner flex-basis-Eigenschaft.

Ich habe unser vorheriges Beispiel angepasst, indem ich flex-basis zu jedem Element hinzugefügt habe. Hier ist der Pen für Sie.

Elternbreite: 900px
Abschnittsbreite: 400px (flex-basis-Wert)
Aside-Breite: 200px (flex-basis-Wert)
Gesamte flex-grow-Werte: 3

1. Berechnen Sie den verbleibenden Platz

900 - 400 - 200 = 300

2. Bestimmen Sie, wie viel ein flex-grow ist

300 / 3 = 100

3. Verteilen Sie den zerteilten verbleibenden Platz

400 + (2 * 100) = 600  
200 + (1 * 100) = 300

Nur zur Vollständigkeit: Sie müssen nicht unbedingt Pixelwerte verwenden und hoffen, dass es klappt. Prozentwerte funktionieren auch.

Arbeiten mit dem Box-Modell

Um also alles abzudecken, schauen wir uns an, was passiert, wenn wir Padding und Margin hinzufügen. Nichts Besonderes eigentlich. Im ersten Schritt der Berechnung müssen Sie nur daran denken, auch die Margins abzuziehen.

Das Einzige, was zu beachten ist, ist, dass sich flex-basis in Bezug auf box-sizing wie die width-Eigenschaft verhält. Das bedeutet, dass sich die Berechnung und die Ergebnisse ändern, wenn sich die box-sizing-Eigenschaft ändert. Wenn box-sizing auf border-box gesetzt wäre, würden Sie in Ihrer Berechnung nur mit den Werten für flex-basis und margin arbeiten, da das padding bereits in der Breite enthalten ist.

Einige nützliche Beispiele

Okay, genug der Mathematik. Lassen Sie mich Ihnen einige Beispiele geben, wie Sie flex-grow effektiv in Ihren Projekten einsetzen können.

Kein width: [ x ]% mehr

Da der verbleibende Platz automatisch verteilt wird, müssen wir uns keine Gedanken mehr über Breitenwerte machen, wenn wir möchten, dass unsere Kindelemente das Elternelement ausfüllen.

Siehe den Pen QyWEBb von Manuel Matuzoc (@matuzo) auf CodePen.

Das "Heilige Gral"-3-Spalten-Liquid-Layout mit Pixelbreiten

Das Mischen von festen und flüssigen Breiten in Spaltenlayouts ist mit Float möglich, aber es ist weder intuitiv noch einfach, noch flexibel. Natürlich ist das mit Flexbox und etwas flex-grow und flex-basis-Magie ein Kinderspiel.

Siehe den Pen jbRjMG von Manuel Matuzoc (@matuzo) auf CodePen.

Füllen des verbleibenden Platzes mit beliebigen Elementen

Wenn Sie zum Beispiel neben einem Label ein Eingabefeld haben und möchten, dass das Eingabefeld den restlichen Platz ausfüllt, benötigen Sie keine hässlichen Hacks mehr.

Siehe den Pen eJYdWV von Manuel Matuzoc (@matuzo) auf CodePen.

Weitere Beispiele finden Sie auf Philip Waltons Solved by Flexbox.

Den Spezifikationen lauschen

Laut den Spezifikationen sollten wir die flex-Kurzschreibweise anstelle von flex-grow direkt verwenden.

Autoren werden ermutigt, die Flexibilität über die flex-Kurzschreibweise zu steuern, anstatt direkt über flex-grow, da die Kurzschreibweise nicht spezifizierte Komponenten korrekt zurücksetzt, um gängige Verwendungen zu ermöglichen.

https://drafts.csswg.org/css-flexbox/#flex-grow-property

Aber Vorsicht! Wenn Sie nur flex: 1; verwenden, werden einige der obigen Beispiele nicht mehr funktionieren, da die Werte, die für die gängigen Verwendungen festgelegt sind, nicht den Standardwerten entsprechen und somit unseren Bedürfnissen entgegenwirken.

Wenn Sie flex für unseren Anwendungsfall verwenden möchten, sollten Sie es wie folgt definieren

flex: 2 1 auto;  /* (<flex-grow> | <flex-shrink> | <flex-basis>) */

Flexbox lernen

Wenn Sie mehr über Flexbox erfahren möchten, schauen Sie sich bitte diese großartigen Ressourcen an

Zusammenfassung und Lektionen

Ist flex-grow seltsam? Nein, gar nicht. Wir müssen nur verstehen, wie es funktioniert und was es tut. Wenn ein Element flex-grow auf 3 gesetzt hat, bedeutet das nicht, dass es dreimal so groß ist wie ein Element mit flex-grow auf 1, sondern dass ihm dreimal mehr Pixel zu seiner Anfangsbreite hinzugefügt werden als dem anderen Element.

Ich habe meine Lektion gelernt, indem ich flex-grow mit zwei leeren Elementen getestet habe, was mir ein völlig anderes Verständnis davon vermittelt hat, was die Eigenschaft tatsächlich tut, und das führte natürlich zu falschen Schlussfolgerungen. Man sollte neue Dinge in einer möglichst realistischen Umgebung testen, um den besten Eindruck davon zu bekommen, wie sie wirklich funktionieren und sich verhalten.