12.11. Właściwości flex-basis, flex-grow, flex-shrink

Kontrolowanie elastyczności elementów flex

Podczas gdy właściwości takie jak justify-content i align-items zarządzają wyrównaniem, właściwości flex-basis, flex-grow i flex-shrink kontrolują **rozmiar i elastyczność** poszczególnych elementów flex wzdłuż osi głównej.

Te trzy właściwości są kluczowe dla zrozumienia, jak Flexbox rozdziela przestrzeń i dostosowuje rozmiary elementów.

Stosuje się je bezpośrednio do **elementów flex** (dzieci kontenera), a nie do kontenera.

flex-basis: Rozmiar początkowy

Właściwość flex-basis definiuje **początkowy (bazowy) rozmiar** elementu flex wzdłuż osi głównej, **zanim** zostanie zastosowane rozciąganie (flex-grow) lub kurczenie (flex-shrink).

  • Wartość domyślna: auto. W tym przypadku przeglądarka próbuje użyć wartości właściwości width lub height elementu (w zależności od flex-direction). Jeśli one również są auto, rozmiar jest określany na podstawie zawartości elementu.
  • Wartości długości: Można podać konkretną długość (np. px, em, %). Procenty odnoszą się do rozmiaru kontenera flex wzdłuż osi głównej.
  • content: (Nowsza wartość) Rozmiar bazowy jest określany na podstawie zawartości elementu, podobnie jak przy auto, ale z pewnymi niuansami w obliczeniach.

Można myśleć o flex-basis jak o "sugerowanym" rozmiarze elementu przed rozdzieleniem wolnej przestrzeni.

.item {
  flex-basis: 150px; /* Sugerowany rozmiar początkowy to 150px */
}

.item-auto {
  flex-basis: auto; /* Użyj width/height lub rozmiaru zawartości */
}

.item-percent {
  flex-basis: 25%; /* Sugerowany rozmiar to 25% szerokości kontenera */
}

Uwaga: Jeśli jednocześnie ustawisz flex-basis (inne niż auto) oraz width (przy flex-direction: row) lub height (przy flex-direction: column), to flex-basis ma pierwszeństwo.

flex-grow: Zdolność do rozciągania

Właściwość flex-grow określa, **jaką część dostępnej wolnej przestrzeni** w kontenerze (wzdłuż osi głównej) dany element flex powinien "wchłonąć", jeśli jest taka przestrzeń.

  • Wartość domyślna: 0. Oznacza to, że element domyślnie **nie rośnie**, aby wypełnić wolną przestrzeń. Zachowuje swój rozmiar bazowy (flex-basis).
  • Wartości liczbowe (nieujemne): Określają **proporcję**, w jakiej element ma rosnąć w stosunku do innych elementów flex w tej samej linii, które również mają flex-grow > 0.

Jak to działa?

  1. Obliczana jest całkowita wolna przestrzeń w linii flex.
  2. Sumowane są wartości flex-grow wszystkich elementów w linii.
  3. Każdy element z flex-grow > 0 otrzymuje dodatkową przestrzeń proporcjonalną do jego wartości flex-grow w stosunku do sumy.

Przykład:

<div class="container" style="width: 600px; display: flex;">
  <div class="item item-a">A (grow 1)</div>
  <div class="item item-b">B (grow 2)</div>
  <div class="item item-c">C (grow 0)</div>
</div>
.item {
  flex-basis: 100px; /* Każdy zaczyna od 100px */
  height: 50px; margin: 5px; background: lightblue;
}
.item-a { flex-grow: 1; background: lightcoral; }
.item-b { flex-grow: 2; background: lightgreen; }
.item-c { flex-grow: 0; /* Domyślnie, nie rośnie */ }

Załóżmy, że kontener ma 600px. Elementy mają flex-basis: 100px, więc razem zajmują 300px (plus marginesy, pomińmy je dla uproszczenia). Zostaje 300px wolnej przestrzeni.

Suma flex-grow = 1 (A) + 2 (B) + 0 (C) = 3.

  • Element A dostaje 1/3 wolnej przestrzeni: 300px / 3 = 100px. Jego końcowy rozmiar: 100px (basis) + 100px (grow) = 200px.
  • Element B dostaje 2/3 wolnej przestrzeni: (300px / 3) * 2 = 200px. Jego końcowy rozmiar: 100px (basis) + 200px (grow) = 300px.
  • Element C ma flex-grow: 0, więc nie rośnie. Jego końcowy rozmiar: 100px (basis).

Razem: 200px + 300px + 100px = 600px (cały kontener).

flex-shrink: Zdolność do kurczenia

Właściwość flex-shrink określa, **jaką część "nadmiarowej" przestrzeni** (gdy suma flex-basis elementów przekracza rozmiar kontenera) dany element flex powinien "oddać", aby zmieścić się w kontenerze.

  • Wartość domyślna: 1. Oznacza to, że element domyślnie **może się kurczyć**, jeśli jest to konieczne.
  • Wartości liczbowe (nieujemne): Określają **proporcję**, w jakiej element ma się kurczyć w stosunku do innych elementów flex w tej samej linii, które również mają flex-shrink > 0. Obliczenia są nieco bardziej złożone niż przy flex-grow, ponieważ uwzględniają również flex-basis elementu (większe elementy kurczą się proporcjonalnie więcej).
  • flex-shrink: 0: Element **nie będzie się kurczył** poniżej swojego flex-basis.

Przykład:

<div class="container" style="width: 400px; display: flex;">
  <div class="item item-x">X (shrink 1)</div>
  <div class="item item-y">Y (shrink 2)</div>
  <div class="item item-z">Z (shrink 0)</div>
</div>
.item {
  flex-basis: 200px; /* Każdy chce mieć 200px */
  height: 50px; margin: 5px; background: lightblue;
}
.item-x { flex-shrink: 1; /* Domyślnie */ background: lightcoral; }
.item-y { flex-shrink: 2; background: lightgreen; }
.item-z { flex-shrink: 0; background: lightyellow; } /* Nie kurczy się */

Kontener ma 400px. Suma flex-basis = 200 + 200 + 200 = 600px. Brakuje 200px.

Element Z ma flex-shrink: 0, więc zachowa swoje 200px.

Pozostałe 400px nadmiaru muszą zostać "odjęte" od X i Y. Obliczenie ważone: (shrink * basis) dla X = 1 * 200 = 200; dla Y = 2 * 200 = 400. Suma ważona = 600.

  • X kurczy się o: (200 / 600) * 200px = 66.67px. Końcowy rozmiar: 200 - 66.67 = 133.33px.
  • Y kurczy się o: (400 / 600) * 200px = 133.33px. Końcowy rozmiar: 200 - 133.33 = 66.67px.
  • Z zachowuje 200px.

Razem: 133.33 + 66.67 + 200 = 400px (cały kontener).

(Dokładne obliczenia mogą być skomplikowane, ale kluczowe jest zrozumienie, że flex-shrink kontroluje proporcje kurczenia, a flex-shrink: 0 zapobiega kurczeniu.)

Zadania praktyczne

Zadanie 1 (z rozwiązaniem)

Stwórz kontener flex z trzema elementami. Nadaj wszystkim flex-basis: 100px. Pierwszemu nadaj flex-grow: 1, drugiemu flex-grow: 2, a trzeciemu pozostaw domyślne flex-grow: 0. Obserwuj, jak rozdzielana jest wolna przestrzeń.

Rozwiązanie:

HTML:

<div class="container-task1" style="display: flex; width: 500px; border: 1px solid black;">
  <div class="item item-1">1 (grow 1)</div>
  <div class="item item-2">2 (grow 2)</div>
  <div class="item item-3">3 (grow 0)</div>
</div>

CSS:

.item {
  flex-basis: 100px;
  flex-shrink: 0; /* Wyłącz kurczenie dla prostszego przykładu */
  height: 50px;
  margin: 5px;
  background-color: #eee;
  border: 1px solid #ccc;
}
.item-1 { flex-grow: 1; }
.item-2 { flex-grow: 2; }
.item-3 { flex-grow: 0; }

Efekt: Kontener ma 500px. Suma basis = 300px. Wolna przestrzeń = 200px. Suma grow = 1+2+0 = 3. Element 1 dostanie 1/3 * 200px, Element 2 dostanie 2/3 * 200px, Element 3 nie urośnie. Końcowe szerokości (bez marginesów): ok. 167px, 233px, 100px.

Zadanie 2 (do samodzielnego wykonania)

Stwórz kontener flex o szerokości 300px z trzema elementami. Nadaj wszystkim flex-basis: 150px. Pierwszemu nadaj flex-shrink: 0, drugiemu flex-shrink: 1, a trzeciemu flex-shrink: 2. Obserwuj, jak elementy się kurczą (lub nie).

Zadanie 3 (do samodzielnego wykonania)

Stwórz typowy układ nagłówka z logo po lewej i nawigacją po prawej. Użyj Flexbox. Nadaj logo flex-grow: 0 i flex-shrink: 0 (aby zachowało swój rozmiar), a kontenerowi nawigacji nadaj flex-grow: 1, aby wypełnił pozostałą przestrzeń.

FAQ - Najczęściej zadawane pytania

Jakie są domyślne wartości flex-basis, flex-grow, flex-shrink?

Domyślne wartości to: flex-basis: auto, flex-grow: 0, flex-shrink: 1. Oznacza to, że element domyślnie bierze rozmiar z width/height lub zawartości, nie rośnie, ale może się kurczyć.

Co oznacza flex-grow: 1 na wszystkich elementach?

Jeśli wszystkie elementy w linii mają flex-grow: 1, oznacza to, że cała dostępna wolna przestrzeń zostanie równo rozdzielona między nimi.

Kiedy używać flex-basis zamiast width/height?

flex-basis jest bardziej