Kilka lat temu usiadłem, aby zbudować dashboard. Nic wielkiego — tylko stały pasek boczny, główny obszar treści i stopka. Flexbox wydawał się oczywistym wyborem i początkowo działał poprawnie. Potem wrzuciłem rząd kart do głównej sekcji. Cały układ się rozsypał. Spędziłem kolejne trzy godziny, walcząc z proporcjami flex-grow i zagnieżdżonymi szerokościami procentowymi, patrząc, jak kontenery odmawiają ustawienia się w linii, bez względu na to, ile paddingu bym nie odjął. Strona przypominała wieżę, która zaraz ma runąć.

To bolesne doświadczenie nauczyło mnie najważniejszej rzeczy na temat nowoczesnych układów CSS: Flexbox i Grid nie są rywalami. To narzędzia do różnych zadań, a większość nieudanych układów wynika z użycia niewłaściwego z nich.

Różnica tkwi w wymiarach

Wyobraź sobie Flexbox jako korytarz. Elementy płyną w jednym kierunku, albo w wierszu, albo w kolumnie. Jest on stworzony do rozkładu jednowymiarowego. Przeglądarka analizuje treść, a następnie decyduje, jak ją rozciągnąć, zmniejszyć lub wyrównać wzdłuż tej jednej osi. Dzięki temu Flexbox jest idealny w sytuacjach, gdy to treść dyktuje układ. Pasek nawigacji, stos pól formularza czy zestaw tagów wymagających równego odstępu — wszystko to naturalnie mieści się w kontenerze flex, ponieważ wszystkie te elementy opierają się na jednej linii logiki.

Grid z kolei to plan piętra. Jest ściśle dwuwymiarowy, obsługując wiersze i kolumny jednocześnie. Najpierw definiujesz strukturę, a dopiero potem umieszczasz w niej elementy. To sprawia, że Grid jest idealny do ogólnej architektury strony — wszędzie tam, gdzie musisz kontrolować pozycjonowanie pionowe i poziome jednocześnie. Gdy próbujesz wymusić złożony, dwuwymiarowy projekt za pomocą zagnieżdżonych kontenerów Flexbox, kończysz z głębokim markupiem, kruchymi wrapperami i delikatną matematyką, która rozpada się w momencie dodania jednego dodatkowego elementu.

Flexbox wciąż ma swoje miejsce

Nie spiesz się z zastępowaniem każdego kontenera flex przez Grid. Wewnątrz poszczególnych komponentów Flexbox jest często czystszy i bardziej intuicyjny. Jeśli masz stopkę karty z dwoma przyciskami i chcesz, aby jeden był wyrównany do lewej, a drugi do prawej, justify-content: space-between zrobi dokładnie to, co zamierzasz. Jeśli musisz pionowo wyśrodkować ikonę w przycisku o nieznanej wysokości, align-items: center jest najprostszą drogą. Zmienna treść — jak rząd badge'y użytkowników o różnej długości nazw — dobrze pasuje do Flexboxa, ponieważ działa on w modelu „content-first”. Kontener dostosowuje się do tego, co zawiera.

Grid działa w modelu „container-first”. Mówisz przeglądarce, ile istnieje ścieżek (tracks) i jak duże powinny być, a następnie wrzucasz elementy do tych komórek. Jeśli Twój układ to w rzeczywistości tylko jedna linia elementów dzielących przestrzeń, Grid wprowadza zbędną otoczkę.

Układ strony to domena Grida

To tutaj Grid przejmuje stery. Pamiętasz mój koszmar z dashboardem? Oto jak ta struktura powinna wyglądać od samego początku:

.page {
  display: grid;
  min-height: 100vh;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 200px 1fr;
}

.header { grid-row: 1; grid-column: 1 / -1; }
.sidebar { grid-row: 2; grid-column: 1; }
.main { grid-row: 2; grid-column: 2; }
.footer { grid-row: 3; grid-column: 1 / -1; }

Zobacz, co się dzieje. Kontener .page tworzy trzy wiersze i dwie kolumny. Pierwszy wiersz dopasowuje swoją wysokość do zawartości nagłówka dzięki auto. Środkowy wiersz zajmuje całą pozostałą dostępną przestrzeń za pomocą 1fr. Stopka trafia do ostatniego wiersza, dopasowanego do własnej zawartości. W międzyczasie pasek boczny ma stałą szerokość 200 pikseli, a główny obszar wypełnia resztę.

Logika rozmieszczenia to prawdziwa ulga. Nagłówek rozciąga się od linii kolumny 1 do linii -1, co oznacza, że rozciąga się na obie kolumny, niezależnie od tego, ile kolumn dodasz później. Pasek boczny i główna treść współdzielą wiersz 2, ale zajmują osobne kolumny. Stopka wraca do pełnej szerokości w wierszu 3. Nie potrzebujesz obliczeń procentowych dla elementów potomnych. Nie potrzebujesz zagnieżdżonych wrapperów walczących o wysokość. Zmień szerokość paska bocznego w jednym miejscu, a główny obszar dostosuje się automatycznie. Cały układ oddycha jako jeden spójny system.

Czytelność dzięki grid-template-areas

Dla jeszcze większej przejrzystości możesz nazwać swoje sekcje. Zamiast zarządzać numerami linii, tworzysz wizualną mapę:

.page {
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
}

.header { grid-area: header; }
.main { grid-area: main; }

Teraz Twój arkusz stylów czyta się jak makieta. Jeśli kiedykolwiek będziesz chciał, aby pasek boczny pojawił się po prawej stronie dla innego breakpointu, po prostu zamieniasz dwa słowa w ciągu szablonu. Tego rodzaju strukturalna czytelność jest nieosiągalna w wieży zagnieżdżonych kontenerów flex.

Dwie trudne lekcje

Grid nie jest magią. Istnieją dwa błędy, które szybko zrujnują Twój układ.

Pierwszym problemem jest niechlujne stosowanie jednostek. Jeśli zdefiniujesz grid-template-columns: 1fr 1fr 1fr, ale Twój projekt wymaga tylko dwóch kolumn treści, ta trzecia ścieżka nadal istnieje. Będzie ona albo pusta, tworząc nieoczekiwaną przerwę, albo zmusi Twoją właściwą treść do ściskania się w sposób, który zepsuje Twój projekt. Działaj świadomie. Jeśli masz na myśli dwie kolumny, napisz repeat(2, 1fr).