Flexbox czy CSS Grid: kiedy użyć którego, podstawy i najczęstsze problemy

Mateusz Bogolubow

24-10-2026

(aktualizacja: 24-10-2026)

Czym różnią się Flexbox i CSS Grid, kiedy wybrać który i skąd biorą się najczęstsze problemy: rozpychanie elementów, 1fr, centrowanie i ostatni wiersz. Z pomiarami w przeglądarce.

Flexbox czy CSS Grid: kiedy użyć którego, podstawy i najczęstsze problemy
Flexbox układa elementy w jednej osi (w rzędzie albo w kolumnie), a CSS Grid w dwóch naraz (w wierszach i kolumnach). Flexboxa używaj do menu, pasków narzędzi i wyśrodkowania, a Grida do układu całej strony i siatek kart. Oba można łączyć: Grid na układ strony, a Flexbox wewnątrz poszczególnych elementów.

Flexbox i CSS Grid to dwa narzędzia do układania elementów na stronie, które zastąpiły dawne sztuczki z float i tabelami. Początkujący często pytają, którego z nich użyć, a potem tracą godziny na układ, który „sam się rozjeżdża”. W tym artykule pokażę podstawy obu, kiedy wybrać który i skąd biorą się najczęstsze problemy. Wszystkie przykłady sprawdziłem w przeglądarce, a podane wymiary to wyniki pomiaru, a nie wyliczenia „na oko”.

Czym różnią się Flexbox i CSS Grid?

Najważniejsza różnica to liczba osi:

FlexboxCSS Grid
Układjednowymiarowy (jedna oś: rząd albo kolumna)dwuwymiarowy (wiersze i kolumny)
Skąd bierze rozmiaryz zawartości elementów („od środka”)z zadeklarowanej siatki („od zewnątrz”)
Włączasz godisplay: flex na rodzicudisplay: grid na rodzicu
Typowe zastosowaniemenu, pasek narzędzi, karta, wyśrodkowanieukład strony, siatka kart, formularze

Oba działają według tej samej zasady: ustawiasz właściwość na rodzicu (kontenerze), a jego bezpośrednie dzieci stają się elementami układu. Wnuki nie są już objęte tym układem.

Jak działa Flexbox? Osie i wyrównanie

Po wpisaniu display: flex dzieci układają się w rzędzie. Masz wtedy dwie osie: główną (domyślnie pozioma) i poprzeczną (pionowa). Wyrównanie na każdej z nich ustawiają dwie właściwości:

  • justify-content – wyrównanie wzdłuż osi głównej,
  • align-items – wyrównanie wzdłuż osi poprzecznej.
<style>
  .k { display: flex; width: 300px; height: 100px; justify-content: center; align-items: flex-end; }
  .k > div { width: 50px; height: 20px; }
</style>
<div class="k"><div>1</div><div>2</div></div>

Pomiar: elementy stoją na środku poziomo (lewy brzeg pierwszego na x = 100) i przy dolnej krawędzi (y = 80, czyli 100 − 20). Teraz zmień kierunek osi głównej na kolumnę (flex-direction: column):

<style>
  .k { display: flex; flex-direction: column; width: 300px; height: 100px; justify-content: center; align-items: flex-end; }
  .k > div { width: 50px; height: 20px; }
</style>
<div class="k"><div>1</div><div>2</div></div>

Teraz justify-content: center centruje elementy w pionie (pierwszy ma y = 30), a align-items: flex-end przesuwa je w prawo (x = 250). Właściwości zostały te same, ale zamieniły się kierunki, bo osie zamieniły się miejscami. To najczęstsze źródło pomyłek, a samo zagadnienie opisaliśmy też w artykule o myleniu właściwości justify- i align- we flexboxie.

Jak dzielić miejsce we Flexboxie? flex: 1, rosnące i kurczące się elementy

Elementy flexboxa potrafią rosnąć (flex-grow) i kurczyć się (flex-shrink), żeby wypełnić kontener. Skrót flex: 1 oznacza „weź swoją część wolnego miejsca”. Liczba to waga:

<style>
  .k { display: flex; width: 600px; }
  .k > div { height: 10px; }
  .a { flex: 1; }
  .b { flex: 2; }
  .c { width: 100px; }
</style>
<div class="k"><div class="a"></div><div class="b"></div><div class="c"></div></div>

Pomiar szerokości: 167 px, 333 px i 100 px. Element .c ma stałe 100 px, a pozostałe 500 px dzielą się w stosunku 1 : 2. Drugą stroną jest kurczenie. Gdy elementy nie mieszczą się w kontenerze, flexbox domyślnie je zmniejsza:

<style>
  .k { display: flex; width: 300px; }
  .k > div { height: 10px; width: 200px; }
  .n { flex-shrink: 0; }
</style>
<div class="k"><div></div><div class="n"></div></div>

Dwa elementy po 200 px w kontenerze 300 px: pierwszy skurczył się do 100 px, a drugi z flex-shrink: 0 został przy 200 px (razem 300 px, czyli dokładnie tyle, ile ma kontener).

Jak zawinąć elementy do kolejnego wiersza? flex-wrap i gap

Domyślnie flexbox nie zawija elementów. Zamiast przenieść element do nowej linii, ściska wszystkie w jednej. To odpowiedź na popularne pytanie „dlaczego mój flexbox się nie zawija”:

<style>
  .k { display: flex; width: 300px; gap: 10px; }
  .k > div { width: 120px; height: 10px; }
</style>
<div class="k"><div></div><div></div><div></div></div>

Trzy elementy po 120 px w kontenerze 300 px zostały ściśnięte do 93 px każdy. Dopisz flex-wrap: wrap, a trzeci element przeskoczy do drugiego wiersza, zachowując swoje 120 px:

<style>
  .k { display: flex; flex-wrap: wrap; width: 300px; gap: 10px; }
  .k > div { width: 120px; height: 10px; }
</style>
<div class="k"><div></div><div></div><div></div></div>

Właściwość gap ustawia odstępy między elementami, dzięki czemu nie potrzebujesz marginesów, które trzeba osobno zerować na krawędziach.

Jak działa CSS Grid? Kolumny, fr i grid-template-areas

W Gridzie najpierw definiujesz siatkę na rodzicu, a potem elementy wpadają do kolejnych komórek. Jednostka fr oznacza „jedną część wolnego miejsca”. Element może też zająć kilka komórek, np. dzięki grid-column: span 2:

<style>
  .g { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; width: 620px; }
  .g > div { height: 20px; }
  .s { grid-column: span 2; }
</style>
<div class="g"><div class="s"></div><div></div><div></div><div></div><div></div></div>

Pomiar: trzy kolumny po 200 px (620 − 2 × 10, podzielone na 3), a pierwszy element zajmuje dwie kolumny i ma 410 px (2 × 200 + odstęp). Dla całych układów stron wygodny jest zapis obszarami:

<style>
  .g {
    display: grid; width: 600px; height: 300px;
    grid-template-columns: 150px 1fr;
    grid-template-rows: 50px 1fr 40px;
    grid-template-areas:
      "naglowek naglowek"
      "menu     tresc"
      "stopka   stopka";
  }
  .n { grid-area: naglowek; }
  .m { grid-area: menu; }
  .t { grid-area: tresc; }
  .s { grid-area: stopka; }
</style>
<div class="g"><div class="n"></div><div class="m"></div><div class="t"></div><div class="s"></div></div>

Nagłówek i stopka rozciągają się na całą szerokość (600 px), menu ma 150 px, a treść zajmuje resztę (450 px). Kod czyta się niemal jak szkic strony.

Jak zrobić responsywną siatkę bez media queries? auto-fit i auto-fill

Zapis repeat(auto-fit, minmax(150px, 1fr)) mówi: „zmieść tyle kolumn o szerokości co najmniej 150 px, ile się da, i rozciągnij je”. Przy zmianie szerokości okna liczba kolumn zmienia się sama. Dwa słowa kluczowe różnią się zachowaniem przy małej liczbie elementów:

<style>
  .g { display: grid; gap: 10px; width: 800px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
  .g > div { height: 20px; }
</style>
<div class="g"><div></div><div></div></div>

Dla dwóch elementów w kontenerze 800 px sprawdziłem oba warianty:

ZapisSzerokość elementu
repeat(auto-fit, minmax(150px, 1fr))395 px (elementy rozciągają się na całą szerokość)
repeat(auto-fill, minmax(150px, 1fr))152 px (zostają puste kolumny po prawej)

auto-fit zwija puste kolumny, więc elementy się rozciągają, a auto-fill je zostawia. Większe zmiany układu, np. przejście z trzech kolumn do jednej z innym menu, nadal rozwiązuje się zwykle media queries.

Flexbox czy Grid? Kiedy użyć którego

Prosta zasada: jeśli układasz elementy w jednej linii (nawet zawijanej), sięgnij po Flexbox. Jeśli myślisz o wierszach i kolumnach naraz, użyj Grida. Poniżej typowe sytuacje:

SytuacjaLepszy wybórDlaczego
Menu poziome, pasek narzędziFlexboxjeden rząd, rozmiar zależy od zawartości
Wyśrodkowanie jednego elementuFlexbox lub Gridoba zrobią to w dwóch linijkach
Układ całej strony (nagłówek, menu, treść, stopka)Griddwa wymiary i obszary
Siatka kart lub zdjęćGridrówne kolumny bez kombinowania
Karta (obrazek, tytuł, przycisk w pionie)Flexbox (column)jedna oś, przycisk można „dociągnąć” do dołu
Formularz z etykietami po lewej i polami po prawejGridkolumny wyrównane między wierszami

W prawdziwych projektach używa się obu naraz. Grid układa duże bloki strony, a Flexbox porządkuje wnętrze każdego z nich, np. przyciski w pasku.

Uwaga mentora: nie wybieraj narzędzia dlatego, że „Grid jest nowszy”. Zadaj sobie jedno pytanie: układam elementy w jednej linii czy w siatce? Linia to Flexbox, siatka to Grid. W praktyce i tak użyjesz obu naraz.

Czy zawsze potrzebuję Flexboxa albo Grida?

Nie. To częsty błąd początkujących, którzy po poznaniu Flexboxa dopisują display: flex do każdego kontenera. Jeśli elementy mają stać jeden pod drugim, wystarczy zwykły układ blokowy, który przeglądarka stosuje domyślnie dla elementów takich jak div, p czy section:

<style>
  .k { width: 300px; }
  .k > div { height: 20px; margin-bottom: 10px; }
</style>
<div class="k"><div>Tytuł</div><div>Opis</div><div>Przycisk</div></div>

Pomiar: trzy elementy ułożyły się w pionie (y = 0, 30, 60), każdy na całą szerokość kontenera (300 px). Dokładnie taki sam układ da display: flex; flex-direction: column; gap: 10px, tylko po co komplikować kod, skoro efekt jest identyczny.

Flexbox w kolumnie jest wart użycia dopiero wtedy, gdy potrzebujesz czegoś, czego układ blokowy nie umie, np. „docisnąć” ostatni element do dołu kontenera o określonej wysokości:

<style>
  .k { display: flex; flex-direction: column; width: 300px; height: 200px; }
  .k > div { height: 20px; }
  .k > div:last-child { margin-top: auto; }
</style>
<div class="k"><div>Tytuł</div><div>Opis</div><div>Przycisk</div></div>

Przycisk stoi teraz na y = 180, czyli przy dolnej krawędzi kontenera 200 px. Bez Flexboxa, w zwykłym układzie blokowym, ten sam kontener zostawia go zaraz pod opisem (y = 40). Zasada jest prosta: najpierw sprawdź, czy wystarczy zwykły display: block, a Flexboxa albo Grida dodaj dopiero wtedy, gdy rzeczywiście potrzebujesz wyrównania, zawijania lub siatki. Krótszy CSS łatwiej utrzymać i trudniej w nim o niespodzianki.

Jak wyśrodkować element w poziomie i w pionie?

To jedno z najczęściej wyszukiwanych pytań o CSS. Masz trzy proste sposoby, a wynik jest identyczny. W kontenerze 400 × 200 px element 100 × 50 px ląduje w każdym z nich w tym samym miejscu (x = 150, y = 75):

/* 1. Flexbox */
.k { display: flex; justify-content: center; align-items: center; }

/* 2. Grid: najkrótszy zapis */
.k { display: grid; place-items: center; }

/* 3. Flexbox + automatyczne marginesy elementu */
.k { display: flex; }
.k > div { margin: auto; }

Wyśrodkowanie w pionie działa tylko wtedy, gdy kontener ma wysokość. Jeśli jej nie ustawisz, kontener ma tylko tyle, ile zajmuje zawartość, i nie ma co centrować. W teście kontener bez height miał 50 px wysokości (tyle co element), więc align-items: center nic nie zmieniał. Ustaw height, min-height (np. min-height: 100vh) albo wysokość odziedziczoną od rodzica.

Przy okazji: margin-left: auto na jednym elemencie flexboxa „odpycha” go na koniec osi. Tak powstaje klasyczne menu z logo po lewej i przyciskami po prawej:

<style>
  .k { display: flex; width: 500px; }
  .k > div { width: 50px; height: 10px; }
  .p { margin-left: auto; }
</style>
<div class="k"><div></div><div></div><div class="p"></div></div>

Trzeci element stoi na x = 450, czyli przy prawej krawędzi kontenera 500 px.

Dlaczego element „rozpycha” układ we Flexboxie? min-width: 0

Elementy flexboxa mają domyślnie minimalną szerokość równą szerokości swojej zawartości (min-width: auto). Jeśli w środku jest długi tekst bez spacji, element nie skurczy się poniżej niego, nawet gdy kontener jest węższy. Wyświetlenie wielokropka (text-overflow: ellipsis) wymaga zawężonego elementu, więc często „nie działa”:

<style>
  .k { display: flex; width: 300px; }
  .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
</style>
<div class="k">
  <div class="w"><div class="t">bardzodlugitekstbezspacji_bardzodlugitekstbezspacji_bardzodlugitekstbezspacji</div></div>
</div>

Pomiar: element .w (bezpośrednie dziecko flexboxa) ma 739 px w kontenerze 300 px, więc wielokropek się nie pojawia, bo .t ma tyle miejsca, ile potrzebuje. Rozwiązaniem jest jedna linijka na elemencie flexboxa:

.w { min-width: 0; }

Po jej dodaniu .w ma 300 px, a tekst w środku zostaje obcięty z wielokropkiem. Jeśli sam element flexboxa ma overflow: hidden, to ograniczenie min-width: auto w ogóle nie obowiązuje, dlatego problem pojawia się zwykle wtedy, gdy ograniczasz dopiero zagnieżdżony element.

Dlaczego kolumna 1fr w Gridzie robi się za szeroka? minmax(0, 1fr)

W Gridzie to samo zjawisko występuje pod inną postacią. Zapis 1fr oznacza w rzeczywistości minmax(auto, 1fr), czyli kolumna nie zejdzie poniżej szerokości zawartości. Długi tekst rozpycha kolumnę i zgniata sąsiednią:

<style>
  .g { display: grid; grid-template-columns: 1fr 1fr; width: 400px; }
  .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
</style>
<div class="g">
  <div><div class="t">bardzodlugitekstbezspacji_bardzodlugitekstbezspacji_bardzodlugitekstbezspacji</div></div>
  <div>B</div>
</div>

Dwie kolumny po 1fr w kontenerze 400 px wyszły 739 px i 10 px (druga kolumna została ściśnięta do samego odstępu). Wystarczy zamienić 1fr na minmax(0, 1fr):

.g { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

Wtedy kolumny mają po 200 px. To dobre rozwiązanie, gdy w komórkach Grida pojawiają się długie adresy, tabele albo bloki kodu.

Dlaczego ostatni wiersz wygląda inaczej we Flexboxie niż w Gridzie?

Flexbox układa wiersze niezależnie od siebie. Jeśli zawiniesz pięć elementów z flex: 1 1 30%, ostatni wiersz zawiera tylko dwa, które rozciągną się na całą szerokość. Grid zachowuje kolumny:

Układ (kontener 640 px, 5 elementów, odstęp 10 px)Szerokość elementów w drugim wierszu
Flexbox: flex: 1 1 30% z flex-wrap: wrap315 px (rozciągnięte)
Grid: repeat(3, 1fr)207 px (w kolumnach jak wyżej)

Jeśli zależy Ci na równej siatce, użyj Grida. Flexbox lepiej sprawdza się, gdy to właśnie rozciągnięcie jest oczekiwane.

Jakie błędy z Flexboxem i Gridem zdarzają się najczęściej?

BłądSkutekJak naprawić
mylenie justify- i align- po zmianie flex-directionwyrównanie „w złą stronę”pamiętaj: justify- to oś główna, align- poprzeczna
display: flex tam, gdzie elementy mają stać jeden pod drugimzbędna komplikacja koduzostaw zwykły układ blokowy
brak flex-wrap: wrapelementy ściśnięte w jednej liniidopisz flex-wrap: wrap
brak min-width: 0 na elemencie flexboxatekst rozpycha układ, brak wielokropkamin-width: 0 na elemencie flexboxa
1fr zamiast minmax(0, 1fr)kolumna rozpychana zawartościązamień na minmax(0, 1fr)
wyśrodkowanie w pionie bez wysokości konteneraelement nie jest w środkuustaw height lub min-height
display: flex na „wnuku”układ nie działaukład obejmuje tylko bezpośrednie dzieci rodzica
zmiana kolejności przez order lub pozycjonowanie w Gridziekolejność Tab i czytnika ekranu zostaje według kodu HTMLzmieniaj kolejność w HTML, a nie tylko wizualnie

Ostatni punkt to wiedza z dokumentacji, której nie sprawdzałem testem. Przy układach, w których kolejność wizualna różni się od kolejności w kodzie, zawsze przejdź stronę klawiszem Tab.

Podsumowanie

Flexbox układa elementy w jednej osi, a Grid w dwóch. Do menu, pasków i wyśrodkowania wybierz Flexbox, do układu strony i siatek kart Grid, a w większych projektach używaj obu naraz. Gdy układ „się rozjeżdża”, najczęściej winne są: brak zawijania, brak min-width: 0, 1fr zamiast minmax(0, 1fr) albo kontener bez wysokości. Jeśli chcesz poznać frontend od podstaw z mentorem, zobacz nasz kurs JavaScript.

Konsultacja i warsztaty devmentor.pl

Masz pytania?

Partnerzy

Firmy, z którymi współpracujemy

To partnerzy odpowiedzialni za staże po naszych kursach. Organizują je dla najlepszych absolwentów.

Zobacz wszystkich partnerów →
  • VR Medical
  • Sophona
  • Robot Force