Pořád se něco učíme. Abych se naučil layouty v CSS, napsal jsem o nich knížku.
Opravdu. Nemyslete si, že jsem si prostě jen sedl k počítači a začal sepisovat to, co jsem měl v hlavě. O gridu a flexboxu jsem toho před třemi lety nevěděl zase o tolik více než průměrný frontendista.
Jedna z metod psaní knížky obnášela nakódování desítek častých webových layoutů. Nejprve flexboxem, který jsem uměl lépe. Pak gridem.
Překvapilo mě, že skoro vždy bylo nakonec řešení pomocí gridu efektivnější, přehlednější. Vlastně celkově lepší.
Nejdůležitější praktická kodérská znalost, kterou jsem při práci na knížce získal, bylo to, že skoro vždy preferuji grid před flexboxem. V tomhle textu vám ukážu důvody, proč tomu tak je.
Flexbox vs. grid
Začneme obecnou rovinou. V knížce mám pro srovnání těchto dvou systémů pro tvorbu layoutu takovou pěknou tabulku:
Vlastnost | Flexbox | Grid |
---|---|---|
Jednorozměrný layout | + | + |
Dvourozměrný layout | + | |
Layout z obsahu | + | ? |
Layout z mřížky | + | |
Kompatibilita v MSIE | + | ? |
Už tady je trochu vidět, že v obecné rovině výhody gridu převládají:
- Grid je určený pro dvourozměrný layout (vodorovný i svislý směr), ale zvládnete s ním i ten jednorozměrný (v jednom ze směrů).
- Flexbox byl navržený pro takzvaný „content out“ layout, kdy se layout vytváří na základě obsahu, což je důležitá, ale ne tak častá potřeba kodérek a kodérů. Grid více odpovídá naší představě o layoutu – chceme, abychom layout kontrolovali my, ne obsah, takzvaně „grid in“.
- Dříve byla velkou výhodou flexboxu jeho slušná komptatibilita s MSIE. Podpora gridu v tomto dnes již neslavném prohlížeči nějaká byla, ale šlo o pověstné škrábání levou nohou za pravým uchem. Navíc – Explorer je už mrtvý.
Grid byl vymyšlený pro vyřešení většiny layoutů na webu. Flexbox má pak řešit specifické případy.
Flexbox ale stále vládne
Tohle téma mě zajímá, a tak občas na sociálních sítích dělám průzkumy mezi vývojářkami a vývojáři.
Preferují flexbox nebo grid? Vypadá to, že stále flexbox.
Na Twitteru mi v březnu 2021 odpovědělo 55 % lidí (ze 162), že flexbox považují za výchozí pro svoji práci. U pětiny to byl grid a u čtvrtiny záleží na případu použití.
Podobnou anketu jsem letos zopakoval ve skupině Frontendisti.cz na Facebooku. Flexbox preferuje 30 % (z více než 300 hlasující), grid jen necelá desetina. Zbytek se rozhoduje podle situace, což je asi nejlepší odpověď, protože opravdu záleží na layoutu.
Co je za preferencí flexboxu u webařů?
- Hlavní důvod je v tom, že flexbox působí jednodušeji.
- Další podstatná příčina je jeho kompatibilita s MSIE, která se ve své době velmi hodila.
- No a třetí důvod vyplývá z druhého. Flexbox jsme se kvůli MSIE nějak naučili a na velkou část rozvržení prostě stačí.
Je samozřejmě otázkou, jak moc optimální jsou layouty nakódované skoro vždy flexboxem. Zkusme se zamyslet, zda to nejde lépe.
Důvod první: robustnost gridu
Díky zaměření gridu na tzv. „grid in“ layout byli autoři specifikace nucení promýšlet daleko více případů použití. Specifikace je tedy rozsáhlejší, což mnohé odradí. Ale díky tomu je i robustnější.
Co vše můžete gridem udělat nad rámec obyčejných layoutů? Uvedu zde pár příkladů:
- Pomocí vlastnosti
grid-area
můžete umístit jakéhokoliv potomka na jakékoliv místo mřížky. - Hodnota
dense
vlastnostigrid-auto-flow
částečně nechává vykreslení layoutu typu masonry na prohlížeči. - I grid se může přizpůsobovat obsahu (viz klíčová slova
min-content
amax-content
ve funkciminmax()
). - Grid můžete (podobně jako flexbox) použít nejen blokově (
display:grid
), ale také v řádce (display:inline-grid
). - Z gridu vycházejí nové typy rozvržení jako podmřížka (subgrid) nebo masonry.
Podobně jako mnozí z vás, jsem i já historicky preferoval flexbox. Na většinu běžných layoutů mi stačil. V momentě, kdy jsem se začal věnovat gridu, postupně začalo docházet k přeorientování na mřížku.
Došlo to tak daleko, že jsem nedávno sám sebe načapal při přemýšlení, jestli existují layouty, u kterých je výhodnější použít flexbox. Ano, na pár si jich vzpomenu, ale moc jich není. Ještě se u toho v textu pozastavím později.
Důvod druhý: plnohodnotný Box Alignment
CSS Box Align je modul CSS, který definuje zarovnání v jakémkoliv rozvržení, ať už je to grid nebo flexbox.
Na flexboxu je ovšem nešťastné, že pro něj neplatí všechny vlastnosti zarovnání boxů.
Také následující tabulka je z knížky:
Hlavní osajustify-* |
Příčná osaalign-* |
Oba směryplace-* |
|
---|---|---|---|
Zarovnání položek*-items |
justify-items |
align-items flex, grid |
place-items |
Zarovnání sebe sama*-self |
justify-self |
align-self flex, grid |
place-self |
Distribuce obsahu*-content |
justify-content flex, grid |
align-content flex, grid |
place-content flex, grid |
Je to tak.
Vlastnosti justify-items
i justify-self
nejsou dostupné pro layouty tvořené flexboxem.
Tím pádem nemůžeme ani použít skvělé zkratky pro obousměrné zarovnání – place-items
a place-self
.
Namísto justify-items
můžeme použít starý dobrý margin
nebo pro centrování položek ve flexboxu na příčné ose třeba justify-content
.
Jenže tím to trochu hackujeme, justify-content
je ve skutečnosti určný pro distribuci mezer mezi položkami.
Jaký je důvod pro nepřítomnost některých vlastností Box Alignment ve flexboxu? Rozličné zaměření flexboxu a gridu.
Když jsem to ve specifikaci studoval pro potřeby psaní knížky, chvíli jsem nemožnosti použít tyto vlastnosti rozuměl. Je to složité. Dnes už vám to bohužel vysvětlit neumím. (Vy si to můžete dostudovat například na Stack Overflow.)
Každopádně v kodérské praxi je nutnost pamatovat si, co ve flexboxu používat můžu a co ne, velice nepříjemná.
Pojďme na příklad. Chci v obou směrech centrovat boxík uvnitř rodičovského prvku. Asi jako na obrázku.
HTML:
<div class="container">
<p class="item" contenteditable>
Jsem uprostřed!
</p>
</div>
CSS řešení flexboxem:
.container {
display: flex;
}
.item {
align-self: center;
margin-inline: auto;
}
Ano, můžeme zde použít magickou zkratku, kterou kodéři dnes obvykle používají:
.container {
display: flex;
align-items: center;
justify-content: center;
}
Otázkou je, jestli opravdu kodéři vědí, co přesně tímto dělají.
V gridu je to daleko jednodušší.
Můžeme použít celou škálu zarovnávacích vlastností z tabulky výše.
A tedy i zkratku place-items
pro obousměrné zarovnání.
.container {
display: grid;
place-items: center;
}
Pojďme se ještě podívat na poslední z důležitých důvodů, proč já osobně preferuji mřížku před flexboxem.
Důvod třetí: layout na rodiči
Na gridu mě připadá výhodné, že layouty se vždy vytvářejí na rodiči. Díky tomu existuje jen jeden prvek, který do layoutu promlouvá. A to je rodič.
Vezměme tento jednoduchý příklad layoutu s jedním rodičem a dvěma potomky. Jeden má zabrat třetinu, druhý dvě třetiny šířky.
HTML kód vypadá takto:
<div class="container">
<div class="col-1">
1/3 box
</div>
<div class="col-2">
2/3 box
</div>
</div>
Řešení fleboxem by mohlo být následující:
.container {
display: flex;
gap: 1rem;
}
.col-1 {
flex: 1;
}
.col-2 {
flex: 2;
}
Všimněte si, že používám vlastnost gap
, která je ve flexboxu k dispozici poměrně čerstvě.
Může to být prkotina (a u takovéhoto příkladu to prkotina bezpochyby je), ale to, že máme layout definovaný na potomcích, je z mého pohledu, no… řekněme neoptimální.
Vždy si totiž představím řádově složitější příklady na komplexních webech nebo systémech designu. Tam se kód pro rodiče i potomky může oddělovat do různých souborů. Dokonce je mohou spravovat různí lidé.
Další problém může být v tom, že s vlastností flex
definujete také vlastnost flex-basis
.
Layout se pak může začít chovat jinak, než čekáte.
Stačí, když do něj připluje trošku jiných obsah než jste si představovali - například obrázek namísto textu.
Podívejte se na vysvětlení „modelů pružnosti“ na posledním uvedením odkazu.
Řešení gridem je jednodušší:
.container {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 1rem;
}
Prostě jen kontejneru nastavíme display:grid
a s pomocí grid-template-columns
definujeme, jaké má mít sloupce.
K tomu přidáme mezeru gap:1rem
.
To je vše.
Dobrá tedy. Ale znamená to celé, že na flexbox máme zapomenout? Ne tak docela.
Kam grid nemůže (strčí se flexbox)
Důvody, proč já osobně grid preferuji, už znáte. Už také víte, že jsem se přistihl přitom, že se mi špatně představují situace, kdy bych grid nepoužil. Jenže co já vím – kodéřinou se neživím a moje představivost je omezená.
Proto jsem se na sociálních sítích na příklady ptal i kolegyň a kolegů. (Díky všem za odpovědi! Viz Twitter, Facebook, LinkedIn.)
Když jsme takto dali hlavy dohromady, už víme, že obecně může být flexbox vhodnější, když jde o tyto situace:
- Mám jednosměrný layout a neznámý počet položek v něm.
- Chci, aby se mé rozvržení přizpůsobovalo délce obsahu uvnitř.
- Rád bych, aby se položky automaticky zalamovaly, pokud prostoru není dost.
Jak už jsem uvedl výše, i tyhle případy se dají vyřešit gridem. Fakt jo. Ale bude to samozřejmě trošku složitější.
Vezměme si příklad se štítky. Mám předem neznámý počet štítků:
<ul class="tags">
<li class="tag">Tag</li>
<li class="tag">Tag too</li>
<li class="tag">Tag</li>
</ul>
Štítky se mají zalamovat podle šířky okna.
Nechci zde zbytečně nastavovat Media Queries.
Řešení flexboxem je jednoduché.
Navíc přidám gap
, který je elegantnější než margin
:
.tags {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
}
Gridem to půjde jen částečně a navíc to bude trošku složitější:
.tags {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, max-content));
gap: 0.25rem;
}
Protože máme neznámý počet sloupců, musíme zapojit klíčové slovo auto-fit
s funkcí repeat()
. Dále musíme nastavit šířku podle obsahu, zde díky funkci minmax()
.
Zde prostě gridem pácháme zbytečně složitý kód. A navíc – automatická responzivita zde fungovat nebude. Musíme použít Media Queries, však jde o „grid in“ layout, který musíme mít celý pod kontrolou my jako vývojáři.
Na sítích se díky vám naskytlo pár dalších příkladů, kdy je prostě flexbox jednodušší:
- Zarovnání ikonky v tlačítku (Viz Ondřej Žára. Gridem to jde, ale je to o řádek složitější.)
- Zarovnání formulářových prvků s automatickou responzivitou. (Viz zde.)
- Fotogalerie s důrazem na přizpůsobení velikosti obrázků. (Viz Ondřej Konečný.)
- Kroková navigace, která se přizpůsobuje obsahu a viewportu. (Viz Ondřej Konečný.)
Kdo je vítěz? Ono záleží…
Jak už jsem psal výše, záleží na situaci. Grid je řešení, které mě ve většině případů vyhovuje, ale pro určité konkrétní rozvržení je evidentně flexbox lepší. Hlavně tam, kde má vládnout obsah, není známý počet položek, chceme automatickou responzivitu nebo jde o skutečně velmi jednoduchý layout.
Neměl jsem v úmyslu vás přesvědčovat, abyste se začali grid učit. Ale pokud jsem vám pomohl lépe zmapovat problematiku CSS layoutů, budu moc rád.
Cílem článku a celého mého zamyšlený bylo najít hranice. Mít v hlavě jednoduchý rozhodovací strom, kdy je použít flexbox výhodnější. Více se samozřejmě dozvíte v knížce.
Budu taky rád, když mi napíšete, pokud byste snad v úvaze našli mezeru a nebyl to gap
.
Komentáře
Máte doplnění, komentář nebo jste našli chybu?
Pro přidání názoru se prosím
přihlaste nebo si zřiďte účet.