CSS grid pro mikro layouty
Říká se, že flexbox je nástroj stvořený pro malé layouty. Jeho mladší, zato pokročilejší bratříček CSS grid je zase tolik očekávaným řešením pro velký layout stránky. Co když ale dáme velikost stranou a zaměříme se na to, jaké druhy problémů mohou obě techniky řešit?
CSS grid a flexbox mají hodně společného. Za prvé, nikdy předtím tu nebyl žádný nástroj pro tvorbu layoutu. Kodéři pro ten účel používali techniky určené pro jiné problémy, zejména obtékání obrázků textem (float
) nebo bloky v textu (inline-block
). Obě nové techniky jsou mnohem mocnější. Umí pružně měnit rozměry obsahu, zarovnávat prvky nebo měnit jejich vizuální pořadí. V řadě situací můžeme použít jeden či druhý nástroj se stejným výsledkem. Pojďme se nejprve v rychlosti podívat, v čem se liší.
1D versus 2D
Podobně tradiční, avšak přesnější než naše úvodní rozlišení gridu a flexboxu říká, že flexbox je pro jednorozměrné layouty, naproti tomu grid pro layouty dvourozměrné. Co to znamená?
Přestože u flexboxu definujeme chování prvku ve dvou směrech (neříkal někdo, že flexbox je jednorozměrný?), nedefinuje to žádný vztah mezi jeho řádky. Flexbox sice umí prvky zalomit do více řádků (nebo sloupců, záleží na směru hlavní osy), ty ale o sobě navzájem nemají žádnou informaci a chovají se zcela nezávisle. Flexbox za sebe poskládá prvky tak, jak mu to vyjde. Zalomení se děje pouze automaticky, ovlivnit ho dokážeme jedině šířkou jednotlivých prvků.
Grid definuje layout pro oba směry v ploše: sloupce i řádky. Prvky pak dokážeme do layoutu přesně umístit a máme plnou kontrolu nad výsledkem, což je něco, co flexbox — v obou směrech zároveň — z principu neumožňuje.
Při rozhodování, který z layoutů použít se podle tohoto rozlišení můžeme řídit pravidlem:
- Stačí mi kontrola jen nad řádky nebo jen nad sloupci? Použiji flexbox.
- Potřebuji mít kontrolu nad řádky i sloupci zároveň? Použiji grid.
Content out nebo layout in
Jiný pohled na věc dává otázka, kde chceme layout definovat. V případě flexboxu definujeme většinu vlastností na prvcích, grid zase převážně na kontejneru.
/* Flexbox layout */
.layout {
display: flex;
flex-flow: row wrap;
}
.layout__item {
flex: 1 0 25%;
}
A stejný layout v gridu:
/* Grid layout */
.layout {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto;
}
Jak si i později ukážeme, s flexboxem téměř vždy potřebujeme stylovat prvky layoutu, zatímco s gridem nám často postačí definovat jen kontejner. Také je důležité, že nečekaně velký obsah se u gridu stále udrží v layoutu a ostatní prvky překryje, kdežto flexbox další obsah odsune.
Mezera
Další nezanedbatelný detail je způsob, jakým dokážeme určit rozestupy mezi prvky layoutu. Tady flexbox zatím zůstává pozadu. Jediným v principu podobným způsobem, jakým je nyní možné vložit do flexbox layoutu mezery, je totiž symetrické vnější (nebo vnitřní, záleží, co vyhovuje víc) odsazení na všech prvcích. To ale musí být kompenzované záporným vnějším odsazením flex kontejneru.
/**
* Spacing with flexbox
*
* 1. Add spacing between items.
* 2. Account with the spacing in item width.
* 3. Compensate the spacing on container so the content
* remains aligned with the rest of the page.
*/
.layout {
display: flex;
flex-flow: row wrap;
margin: -0.5rem; /* 3. */
}
.layout__item {
flex: 1 0 calc(25% - 2 * 0.5rem); /* 2. */
margin: 0.5rem; /* 1. */
}
Funkční, ale komplikované. Od dnešního CSS můžeme chtít víc.
Grid naproti tomu přichází se speciálními vlastnostmi pro stanovení mezer: grid-column-gap
a grid-row-gap
, resp. jejich zkratkou grid-gap
. To vede k výsledkům přesně dle očekávání, žádná záporná kompenzace není třeba. Ba co víc, výpočty rozměrů jednotlivých prvků layoutu se nám zjednodušší, protože mezeru do nich nebudeme muset započítávat. Právě práce s mezerou bude v našich dalších ukázkách častějším argumentem, než si teď možná myslíme.
/* Spacing with grid layout */
.layout {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto;
grid-gap: 1rem;
}
Jak je vidět, kód je samodokumentující, není třeba nic vysvětlovat v komentářích.
A pozor, v přípravě (v rámci CSS Box Alignment Module Level 3) je následník, nová CSS vlastnost gap
. Ta má zobecnit existující grid-gap
a bude fungovat pro všechny blokové elementy včetně těch stávajících, tedy např. těch s display: block
nebo display: flex
, takže od záporné kompenzace odsazení budeme moci časem zcela upustit.
/* Spacing of flexbox layout with gap */
/* Works only in FF 63+ as of May 2019 */
.layout {
display: flex;
flex-flow: row wrap;
gap: 1rem;
}
.layout__item {
flex: 1 0 auto;
}
Stále však platí, že gap
a flexbox budou nejlépe fungovat při automatických šířkách prvků, případně pro šířky v součtu menší než celková šířka kontejneru. Rozdělíme-li celý kontejner beze zbytku jako v příkladech výše, mezeru bude z prvků stále třeba odečíst. Flexbox bohužel nemá k dispozici jednotku fr
, která by problém vyřešila.
Nový pohled
Tolik v rychlosti základní rozdíly dvou nejnovějších CSS layoutů, gridu a flexboxu. Když už se v problematice orientujeme, pojďme se podívat na více i méně tradiční návrhové vzory layoutu novýma očima.
Oba přístupy zkusíme porovnat na několika příkladech:
- media: klasický návrhový vzor pro web
- row: řádek s prvky vlevo a vpravo
- notification layout: responzivní layout pro oznámení
- preview layout: složitější responzivní layout např. pro náhled produktu
Media
Snad není příliš odvážné tvrdit, že Media objekt je jeden z neznámějších a nejstarších návrhových vzorů na webu vůbec.
S pomocí flexboxu jej klasicky zapíšeme nějak takto:
/* Media with flexbox */
.media {
display: flex;
align-items: flex-start;
}
.media__figure {
flex: none;
margin-right: 1rem;
}
.media__body {
flex: 1;
}
Přestože jde o jednořádkový layout a s mezerou nemáme problém, zápis pomocí CSS gridu je o polovinu kratší a vypadá velice lákavě:
/* Media with grid */
.media {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 1rem;
align-items: start;
}
Také by vás zprvu nenapadlo grid použít? Pojďme dál.
Row
Opustíme síň slávy návrhových vzorů pro web a vrátíme se k řadovým ukázkám z praxe. Row je úplně jednoduchý layout pro vodorovné rozmístění dvou protilehlých prvků na jednom řádku. Zde se flexbox jeví jako ideální nástroj: jediný řádek, neznámé šířky, automatický rozestup.
/* Row with flexbox */
.row {
display: flex;
align-items: baseline;
}
.row__left,
.row__right {
flex: 0 1 auto;
}
.row__right {
padding-left: 1rem;
margin-left: auto;
}
Snad jen pro bezpečnostní mezeru mezi levým a pravým prvkem by se nám hodila nová vlastnost gap
.
S gridem gap
máme a navíc opět zůstáváme s definicí pouze na kontejneru. Kód znovu zaujme svou přímočarostí a srozumitelností:
/* Row with grid */
.row {
display: grid;
grid-template-columns: auto auto;
grid-column-gap: 1rem;
justify-content: space-between;
align-items: baseline;
}
Notification layout
Další z ukázek, Notification layout, je přenositelný responzivní layout pro upozornění a chybové hlášky. S flexboxem by zápis mohl vypadat nějak takto:
/* Notification layout with flexbox */
.notification-layout {
display: flex;
flex-flow: row wrap;
align-items: center;
}
.notification-layout__icon {
width: 2rem;
margin-right: 1rem;
}
.notification-layout__message {
flex: 1;
}
.notification-layout__cta {
flex: 1 0 100%;
margin-top: 1rem;
}
@media (min-width: 60em) {
.notification-layout {
flex-wrap: nowrap;
}
.notification-layout__cta {
flex: 0 1 50%;
margin-top: 0;
margin-left: 1rem;
}
}
Zatím chybějící gap
opět nahrazujeme odsazením přes margin
, které je třeba anulovat, jakmile je nepotřebujeme.
V grid zápisu využijeme grid-template-areas
, abychom zlepšili čitelnost kódu. Zavedení definic jednotlivých prvků layoutu rovnou využijeme pro roztažení oblasti pro CTA (Call To Action) na mobilu přes celou šířku:
/* Notification layout with grid */
.notification-layout {
display: grid;
grid-template-columns: 2rem 1fr;
grid-template-rows: auto auto;
grid-template-areas:
"icon message"
"cta cta";
grid-gap: 1rem;
align-items: center;
}
@media (min-width: 60em) {
.notification-layout {
grid-template-columns: 2rem 1fr 50%;
grid-template-rows: auto;
grid-template-areas: "icon message cta";
}
}
.notification-layout__icon {
grid-area: icon;
}
.notification-layout__message {
grid-area: message;
}
.notification-layout__cta {
grid-area: cta;
}
Můžeme se také spolehnout na autoplacement algoritmus a kód o něco zkrátit:
/* Notification layout with grid and autoplacement */
.notification-layout {
display: grid;
grid-template-columns: 2rem 1fr;
grid-template-rows: auto auto;
grid-gap: 1rem;
align-items: center;
}
.notification-layout__cta {
grid-column: span 2;
}
@media (min-width: 60em) {
.notification-layout {
grid-template-columns: 2rem 1fr 50%;
grid-template-rows: auto;
}
.notification-layout__cta {
grid-column: span 1;
}
}
Preview layout
Preview layout bude naším posledním a nejsložitějším příkladem. Zatímco na mobilech je toto rozvržení čistě lineární, na větších obrazovkách jsou nároky citelně vyšší: prvky rozmístěné přes více sloupců i řádků, navíc změna jejich vizuálního pořadí. Je jasné, že na takto složité přeskládání layoutu flexbox nestačí, aniž bychom si zkomplikovali HTML kód. Život (ani HTML) si komplikovat nechceme, podívejme se proto rovnou na řešení s gridem.
/* Preview layout with grid */
.preview-layout__title,
.preview-layout__description,
.preview-layout__tags {
margin-bottom: 1rem;
}
@media (min-width: 60em) {
.preview-layout {
display: grid;
grid-template-columns: auto auto 1fr;
grid-template-rows: auto auto;
grid-template-areas:
"title tags cta"
"description description cta";
grid-gap: 1rem;
}
.preview-layout__title,
.preview-layout__description,
.preview-layout__tags {
margin-bottom: 0;
}
.preview-layout__title {
grid-area: title;
align-self: baseline;
}
.preview-layout__description {
grid-area: description;
}
.preview-layout__tags {
grid-area: tags;
align-self: baseline;
}
.preview-layout__cta {
grid-area: cta;
justify-self: end;
align-self: center;
}
}
Grid a Internet Explorer
Přestože Internet Explorer byl první prohlížeč, který CSS grid ve verzi 10 implementoval, ty nejhezčí prvky nové syntaxe bohužel nativně nepodporuje. Jedná se zejména o grid-gap
, grid-template-areas
, align-items
a autoplacement.
Není však na místě házet grid do žita. Autoprefixer vzal otěže do vlastních rukou a částečnou podporu těchto nových vlastností pro Internet Explorer zpřístupňuje emulací. Za určitých podmínek je tak možné v zápisu využít velké části moderních vlastností gridu včetně autoplacementu. Dá sa tak říci, že grid dnes podporují všechny významně zastoupené prohlížeče.
Shrnutí
Flexbox a grid jsou velmi mocné nástroje pro tvorbu layoutu webu. Mají hodně společného, každý z nich přitom zvládá i něco, co ten druhý neumí. Jsou situace, kdy můžeme sáhnout po té či oné technice se stejným výsledkem a bez většího rozdílu v zápisu (Notification layout). Jindy grid překvapí v disciplínách, kde bychom čekali jasnou převahu flexboxu (Media, Row). A jsou chvíle, kdy o flexboxu není ani třeba uvažovat nebo kdy je grid alespoň výrazně efektivnější nástroj než jeho starší kolega (Preview layout).
Shrňme si v krátkosti klíčové poznatky:
- Distribuce a zarovnání jednořádkového obsahu je to, proč byl flexbox navržen. Grid však tyto situace zvládá také a s menší spotřebou kódu.
- Díky
grid-column-gap
,grid-row-gap
agrid-gap
je určování rozestupů mnohem snazší v gridu. Flexbox si musí počkat na novou vlastnostgap
. Ani tak ale nedisponuje jednotkoufr
, která eliminuje nutnost odečtu mezery z šířky prvku. - Udržení stejného layoutu na více řádcích je možné jedině s gridem. Stejně tak kombinace víceřádkových a vícesloupcových prvků.
- Flexbox má zatím výrazně lepší podporu v prohlížečích. S Autoprefixerem však lze grid bezpečně používat i v produkčním prostředí, a to i s některými moderními vlastnostmi.
Nelze říci, že je jedna z technik lepší než druhá. Grid není flexbox a flexbox není grid. V něčem jsou si podobné, přesto jsou jiné. Obojí je však CSS. Oba přístupy nutí k zamyšlení. Jsou to nástroje, které máme k dispozici a v každém jednotlivém případě se můžeme rozhodnout, který z nich nám vyhovuje víc. A především, nikdo nás nebude honit po poli za to, když se zrovna nerozhodneme dobře.
Související odkazy
- Use Cases For Flexbox (Rachel Andrew, Smashing Magazine)
- Best Practices With CSS Grid Layout (Rachel Andrew, Smashing Magazine)
- Quick! What’s the Difference Between Flexbox and Grid? (Chris Coyier, CSS Tricks)
- Relationship of grid layout to other layout methods (MDN)
- Mastering Wrapping of Flex Items (MDN)
- CSS Grid v Internet Exploreru: Jde to! (Martin Michálek, Vzhůru dolů)
Na pracovní ukázky kódu příkladů z tohoto článku se můžete podívat na CodePen.
Další články od autora:
Sdílejte
Líbí se vám článek? Podpořte jej sdílením!
Komentujte
Chcete k článku něco doplnit? Našli jste chybu? Napište e-mail.