Flexbox trafił do wszystkich głównych przeglądarek około 2015 roku i od razu rozwiązał problem, z którym programiści zmagali się od dekady: pionowe wyśrodkowanie. Większość osób nauczyła się go jednak od tyłu — zapamiętała justify-content: center z ściągawki, nie rozumiejąc dlaczego to działa. Gdy układ nie zachowuje się zgodnie z oczekiwaniami, ta luka w wiedzy zamienia pięciominutowe zadanie w godzinę prób i błędów. Ten przewodnik najpierw buduje model mentalny, a następnie omawia każdą właściwość, która naprawdę ma znaczenie w prawdziwych projektach.

Model mentalny: jedna oś naraz

Podstawowa koncepcja Flexboksa polega na tym, że rozmieszcza elementy wzdłuż jednej osi. Istnieje oś główna — kierunek, w którym płyną elementy — oraz oś poprzeczna, biegnąca prostopadle. Kluczowy spostrzeżenie, które umyka prawie każdemu początkującemu: flex-direction określa, która oś jest która. Wszystko inne wynika z tego.

css
/* Default: main axis runs LEFT → RIGHT, cross axis runs TOP → BOTTOM */
.container {
  display: flex;
  flex-direction: row; /* default */
}

/* Rotated: main axis now runs TOP → BOTTOM, cross axis runs LEFT → RIGHT */
.container {
  display: flex;
  flex-direction: column;
}

/*
  justify-content  →  controls alignment on the MAIN axis
  align-items      →  controls alignment on the CROSS axis

  This is why centering something in both axes looks like this:
*/
.center-both {
  display: flex;
  justify-content: center; /* horizontally centred (main axis = row) */
  align-items: center;     /* vertically centred (cross axis)        */
}
Zamieszanie, które myli każdego: gdy przełączysz się na flex-direction: column, justify-content nie kontroluje już wyrównania poziomego — kontroluje wyrównanie pionowe, ponieważ oś główna się obróciła. align-items kontroluje teraz wyrównanie poziome. Pamiętaj o tym obróceniu za każdym razem, gdy coś nie wyrównuje się tam, gdzie się spodziewasz.

Właściwości kontenera

Te właściwości umieszcza się na kontenerze flex — elemencie nadrzędnym z display: flex. Kontrolują one rozkład i wyrównanie wszystkich elementów podrzędnych.

css
/* display: flex makes the element a block-level flex container.
   display: inline-flex makes it inline (sits in text flow). */
.nav {
  display: flex;
}

/* flex-direction — which way does the main axis run? */
.nav {
  flex-direction: row;         /* left to right (default)  */
  flex-direction: row-reverse; /* right to left            */
  flex-direction: column;      /* top to bottom            */
  flex-direction: column-reverse; /* bottom to top         */
}

/* flex-wrap — what happens when items overflow the container? */
.card-grid {
  flex-wrap: nowrap;       /* all items forced onto one line (default) */
  flex-wrap: wrap;         /* items wrap onto additional lines         */
  flex-wrap: wrap-reverse; /* items wrap in reverse order              */
}

/* gap — space between items. Modern approach; avoids margin hacks. */
.card-grid {
  gap: 1.5rem;             /* same in both directions              */
  gap: 1rem 2rem;          /* row-gap column-gap                   */
}

Właściwość gap zasługuje na szczególną wzmiankę. Zanim istniała, powszechnym wzorcem było dodawanie marginesów do elementów flex, a następnie anulowanie zewnętrznych krawędzi ujemnymi marginesami. gap zastępuje to wszystko w czysty sposób — używaj jej wszędzie zamiast tamtego podejścia.

css
/* justify-content — alignment on the MAIN axis */
.nav {
  justify-content: flex-start;    /* packed to start (default)              */
  justify-content: flex-end;      /* packed to end                          */
  justify-content: center;        /* packed to centre                       */
  justify-content: space-between; /* first/last at edges, equal gaps between */
  justify-content: space-around;  /* equal space around each item           */
  justify-content: space-evenly;  /* equal space between every gap          */
}

/* align-items — alignment on the CROSS axis (single line) */
.nav {
  align-items: stretch;   /* items fill cross-axis height (default)         */
  align-items: flex-start;/* items align to start of cross axis             */
  align-items: flex-end;  /* items align to end of cross axis               */
  align-items: center;    /* items centred on cross axis                    */
  align-items: baseline;  /* items aligned by their text baseline           */
}

/* align-content — cross-axis alignment when there are MULTIPLE lines
   (only takes effect with flex-wrap: wrap and enough items to wrap) */
.card-grid {
  flex-wrap: wrap;
  align-content: flex-start;    /* rows packed to top                       */
  align-content: center;        /* rows centred vertically                  */
  align-content: space-between; /* rows spread out with space between       */
}

Oto prawdziwy pasek nawigacji łączący te elementy. Logo znajduje się po lewej stronie, a linki nawigacyjne są przesunięte w prawo za pomocą margin-left: auto — klasyczny trik Flexboksa. Podejście z justify-content: space-between też działa, ale technika z automatycznym marginesem jest bardziej elastyczna, gdy masz więcej niż dwie grupy.

css
/* Nav: logo left, links right */
.site-nav {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0 2rem;
  height: 64px;
  background: #1a1a2e;
}

.site-nav .logo {
  font-size: 1.25rem;
  font-weight: 700;
  color: #fff;
  text-decoration: none;
}

.site-nav .nav-links {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  margin-left: auto; /* pushes everything after it to the right */
  list-style: none;
  margin-top: 0;
  margin-bottom: 0;
  padding: 0;
}

.site-nav .nav-links a {
  color: #ccc;
  text-decoration: none;
  font-size: 0.9rem;
}

.site-nav .nav-links a:hover {
  color: #fff;
}

Właściwości elementów

Te właściwości umieszcza się na elementach flex — bezpośrednich dzieciach kontenera flex. Kontrolują, jak poszczególne elementy rosną, kurczą się i określają własny rozmiar.

  • flex-grow — ile dostępnej wolnej przestrzeni zajmuje ten element. Domyślnie 0 (nie rośnij). Ustawienie 1 na elemencie powoduje, że zajmuje on całą pozostałą przestrzeń.
  • flex-shrink — o ile ten element kurczy się w stosunku do innych, gdy brakuje miejsca. Domyślnie 1. Ustaw na 0, aby zapobiec kurczeniu się elementu.
  • flex-basis — początkowy rozmiar elementu przed jakimkolwiek wzrostem lub kurczeniem. Może być długością (250px, 30%) lub auto (rozmiar zawartości elementu).
  • align-self — nadpisuje align-items dla jednego konkretnego elementu. Przyjmuje te same wartości: auto, flex-start, flex-end, center, baseline, stretch.
  • order — zmienia wizualną kolejność bez modyfikowania HTML. Domyślnie 0. Niższe wartości pojawiają się pierwsze. Używaj oszczędnie — zaburza kolejność tabulacji i powoduje problemy z dostępnością dla użytkowników klawiatury i czytników ekranu.
css
/* Classic sidebar + main content layout */
.app-layout {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  flex: 0 0 280px; /* don't grow, don't shrink, always 280px wide */
  background: #f5f5f5;
  padding: 2rem 1.5rem;
}

.main-content {
  flex: 1; /* grow to fill all remaining space */
  padding: 2rem;
  min-width: 0; /* critical: prevents content overflow in flex children */
}

/* Responsive: stack vertically on mobile */
@media (max-width: 768px) {
  .app-layout {
    flex-direction: column;
  }

  .sidebar {
    flex: none; /* reset — don't use flex-basis on column layout */
  }
}
Pułapka z min-width: 0: domyślnie elementy flex nie mogą się skurczyć poniżej minimalnego rozmiaru zawartości. Jeśli masz długie słowo lub szeroką tabelę wewnątrz elementu flex, przepełni on kontener zamiast zawijać tekst. Dodanie min-width: 0 do elementu flex naprawia ten problem. Pojawia się on stale w głównym obszarze treści w układach z paskiem bocznym.

Skrót flex — wyjaśnienie

Skrót flex łączy flex-grow, flex-shrink i flex-basis w jedną deklarację. Specyfikacja W3C definiuje kilka wartości słów kluczowych obejmujących typowe przypadki, które są często ze sobą mylone.

css
/* flex: 1
   Expands to: flex-grow: 1; flex-shrink: 1; flex-basis: 0%
   Meaning: grow and shrink freely; start from zero (ignore content size).
   All items with flex: 1 share space equally, regardless of content.
   Most common choice for "fill available space". */
.tab { flex: 1; }

/* flex: auto
   Expands to: flex-grow: 1; flex-shrink: 1; flex-basis: auto
   Meaning: grow and shrink freely; start from the item's content size.
   Items with more content get more space — proportional, not equal. */
.column { flex: auto; }

/* flex: none
   Expands to: flex-grow: 0; flex-shrink: 0; flex-basis: auto
   Meaning: completely rigid — don't grow, don't shrink, stay at content size.
   Use for items that should never flex (icons, avatars, fixed labels). */
.avatar { flex: none; }

/* flex: 0 0 200px
   Explicit: don't grow, don't shrink, always exactly 200px.
   Same as writing out all three values. More readable for fixed-size items. */
.sidebar { flex: 0 0 200px; }

/* Practical difference: flex: 1 vs flex: auto in a tab bar
   With flex: 1  → all tabs are equal width regardless of label length
   With flex: auto → "Settings" tab is wider than "Home" tab */
.tabs { display: flex; }
.tab-equal  { flex: 1;    } /* equal width tabs     */
.tab-auto   { flex: auto; } /* content-sized tabs   */

Typowe układy rzeczywiste

Oto cztery wzorce, po które będziesz regularnie sięgać — zbudowane wyłącznie za pomocą Flexboksa.

css
/* 1. Sticky footer
   The footer always sits at the bottom, even on short pages.
   body (or .app-shell) becomes a column flex container. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
}

main {
  flex: 1; /* expands to push footer down */
}

footer {
  /* stays at the bottom */
}
css
/* 2. Centred modal / hero content
   Both axes centred — the Flexbox vertical-centring party trick. */
.hero {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding: 2rem;
  background: linear-gradient(135deg, #667eea, #764ba2);
}

.hero-content {
  max-width: 640px;
  text-align: center;
  color: #fff;
}
css
/* 3. Nav bar: logo left, links right */
.site-nav {
  display: flex;
  align-items: center;
  padding: 0 2rem;
  height: 64px;
}

.site-nav .nav-links {
  margin-left: auto; /* auto margin consumes all free space to its left */
  display: flex;
  gap: 1.5rem;
  list-style: none;
  padding: 0;
  margin-top: 0;
  margin-bottom: 0;
}
css
/* 4. Card row that wraps on mobile */
.card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

.card {
  flex: 1 1 280px; /* grow and shrink, but never below 280px wide */
  background: #fff;
  border-radius: 8px;
  padding: 1.5rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

/* On wide screens: 3-4 cards per row.
   On narrow screens: cards wrap into their own rows automatically.
   No media query needed for the wrap itself — flex-wrap handles it. */

Flexbox kontra Grid — kiedy używać którego

To pytanie pojawia się nieustannie, a odpowiedź jest prostsza, niż sugeruje większość artykułów: Flexbox służy do układów jednowymiarowych. CSS Grid służy do układów dwuwymiarowych. Jeśli rozmieszczasz elementy w jednym wierszu lub jednej kolumnie — pasek nawigacji, grupa przycisków, wiersz kart — Flexbox jest właściwym narzędziem. Jeśli potrzebujesz jednoczesnej kontroli zarówno wierszy, jak i kolumn — pełny układ strony, mozaika fotograficzna, siatka formularza — sięgnij po Grid.

W praktyce będziesz używać obu w tym samym projekcie. Grid obsługuje strukturę na poziomie strony (nagłówek, pasek boczny, główna zawartość, stopka). Flexbox obsługuje komponenty w tych regionach (pasek nawigacji, zawartość karty, grupa przycisków wewnątrz modalu). Uzupełniają się wzajemnie, zamiast ze sobą rywalizować.

Jedna szara strefa: siatki kart, które powinny mieć wiersze o równej wysokości z elementami wyrównanymi w kolumnach. Flexbox z flex-wrap: wrap może to zrobić, ale elementy w tym samym wizualnym wierszu nie mają ze sobą żadnego związku — ich wysokości są niezależne. Niejawne ustalanie rozmiaru wierszy w Grid obsługuje to automatycznie. Jeśli potrzebujesz, aby karty w zawijającym się wierszu miały tę samą wysokość I aby ich wewnętrzne elementy były wyrównane między kartami, Grid jest czystszym rozwiązaniem.

Podsumowanie

Model mentalny Flexboksa to: wybierz kierunek, zrozum, które właściwości kontrolują którą oś, a następnie zdecyduj, czy elementy mają rosnąć, kurczyć się, czy pozostać niezmienne. Gdy to zaskoczy, ściągawka staje się słownikiem, a nie kulą u nogi. Przewodnik MDN po Flexboksie to najlepszy punkt odniesienia dla przypadków brzegowych, a kompletny przewodnik CSS-Tricks pozostaje najużyteczniejszą wizualną ściągawką. W zastosowaniach produkcyjnych obsługa przeglądarek jest praktycznie powszechna — nie są potrzebne prefiksy. Specyfikacja W3C warta jest przejrzenia, gdy napotkasz naprawdę mylący przypadek brzegowy — algorytm jest precyzyjnie udokumentowany i odpowiada na większość pytań „dlaczego to się tak zachowuje".