Masonry layout nativně v CSS

Rozvržení typu masonry je ve webdesignu stejně populární jako zednická lžíce mezi zedníky.

CSS masonry

CSS masonry snad jednou bude součástí specifikace CSS gridu.

Kodérky a kodéři jsou ovšem dneska nucení se s ním vypořádat pomocí JavaScriptu. Nativní implementace v CSS byla součástí našich snů už od příchodu flexboxu, ale plně to nevyřešil ani grid.

Teď už se však snad blýská na lepší časy. Chystaná třetí verze specifikace gridu totiž počítá s možností zápisu hodnoty masonry u vlastností grid-template-rows/columns:

.container {
  display: grid;
  grid-template-rows: masonry;
}

Subgrid má zatím bohužel podporu jen ve verzi Firefoxu Nightly. Je ale možné, že se ujme a že nás zbaví dalšího nadbytečného javascriptového pluginu.

Aktuálně ovšem tuto funkci na webech používat nemůžeme, proto se v článku kromě budoucnosti (nativní implementace v CSS) věnujeme i současnosti (řešení pomocí JS komponent).

Skvěle to (jako vždy) popisuje Rachel Andrew v textu „Native CSS Masonry Layout In CSS grid“ ve Smashing Magazine, ze kterého tady budu vycházet. vrdl.in/smmas

Co je to „masonry“?

Určitě zde jsou tací, kteří o layoutu masonry nic moc nevědí. „Masonry“ je v překladu zdivo, takže jde o „zděné“ rozvržení stránky.

Masonry layout na webu Erika Johanssona

Masonry na webu Erika Johanssona. Jediná vada na kráse je vykreslení pomocí klientského JavaScriptu. erikjo.com/work

Když se položky ve zděném rozvržení přesunou na další řádek, nezarovnávají se do rovné linky, ale přesunou se nahoru do mezer, které zanechají kratší položky v prvním řádku.

Je to podobné jako u jedné z vlastností CSS gridu, automatického umístění (autoplacement), ale bez přísného dodržení mřížky pro řádky. Však se podívejte na obrázek výše, na něm to asi pochopíte nejlépe. Hlavní směr typického masonry je inline, tedy po řádcích.

V současnosti se tyto typy rozvržení dělají pomocí dnes už takřka legendární javascriptové komponenty „Masonry“ od Davida DeSandra.
vrdl.in/mas

Autorovi všechna čest, je však nutné si přiznat, že z pohledu vykreslovacího (ale i načítacího) výkonu stránky nebude takto razantní ovlivňování layoutu JavaScriptem nikdy optimální. Tohle má prostě dělat prohlížeč a autoři to mají definovat v CSS.

Masonry v CSS gridu

Masonry doufejme jednou budeme zapisovat podle specifikace deklaracemi grid-template-rows:masonry nebo grid-template-columns:masonry, podle toho, zda si pro „zdění“ vybereme vodorovný nebo svislý směr.

Směr definovaný pomocí masonry se pak bude označovat jako „osa zdiva“. Druhá osa bude mít stopy mřížky definované jako normální. To bude osa mřížky.

Přikládám CodePen, ale v době psaní bude fungovat jen ve zmíněném Firefox Nightly, takže neuškodí, když si tuto verzi prohlížeče pro zkoušení nových vlastností stáhnete.

CodePen: vrdl.in/i2dgv

V uvedeném prohlížeči si můžete pohrát s hlavním kouskem kódu, který vypadá takto:

.container {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: masonry;
}

Raději to vysvětlím:

  • display:grid definuje layout do mřížky.
  • gap:10px nabádá prohlížeč k vykreslení desetipixelové mezery mezi buňkami.
  • grid-template-columns:repeat(4,1fr) vykreslí čtyři stejně široké sloupce mřížky. Viz zápis repeat().
  • grid-template-rows:masonry zařídí to zděné kouzlo. Řádky nebudou zarovnané podle osy, ale nalepí se na položky výše a přeskupí se. Viz vlastnost grid-template-rows.

Výsledek tohoto zápisu nicméně bez Firefox Nightly lépe uvidíte na následujícím obrázku.

Masonry nativně pomocí CSS

Nativně vykreslený layout typu masonry. Zdroj: CodePen Rachel Andrew.

Je to nativní. Není to krásné?

Napiš řádek kódu,
postav třeba zeď.
Zpívej přitom ódu,
začni s tím hned teď.

Po básnické chvilce, vyvolané vidinou světa bez další javascriptové knihovny, pojďme dál.

Další vlastnosti CSS gridu v masonry? No jasně!

Vzhledem k tomu, že jsme v systému rozvržení pomocí CSS gridu, můžeme používat i další vlastnosti:

  • Stále můžeme porušit automatické umísťování a konkrétní položku vložit na konkrétní místo mřížky. Viz prvek .positioned v tomto CodePenu od Rachel Andrew. vrdl.in/0yh1j
  • Je samozřejmě dovoleno používat i roztažení prvků do více buněk mřížky. To je zase vidět na prvku .landscape v jiném CodePenu. vrdl.in/ar9ex

Vlastnost masonry-auto-flow, kontrola toku položek

Tato vlastnost ještě není naprogramovaná ani ve Firefox Nightly, ale je podobná existující grid-auto-flow. Prostě ovlivňuje, v jakém pořadí se budou položky do zděného rozvržení sázet.

  • Ve výchozím stavu vloží prohlížeč položku do sloupce s největším prostorem.
  • Hodnota next – umístí položku na další místo na ose mřížky.
  • Hodnota ordered – layout bude vždy v pořadí, v jakém jsou položky v dokumentu, pokud není řečeno jinak pomocí vlastnosti order.

Zarovnání pomocí vlastností justify-tracks a align-tracks

V layoutu typu masonry potřebujeme i dvě nové zarovnávací vlastnosti.

Jako by nám nestačily ty desítky, co jich už máme, řekl by bručoun. Ale neměl by pravdu, tento typ zarovnání je úplně nový a nic adekvátního zatím nemáme.

Pokud máte v kontejneru mřížky více prostoru ve směru rozloženém pomocí masonry, zjistíte, že se položky zarovnají na začátek kontejneru. Počáteční hodnota vlastnosti align-tracks je totiž start.

Další možnosti zarovnání jsou podobné jako u vlastností align-content a justify-content (např. end nebo z podstaty věci také space-between), s několika modifikacemi:

  • Hodnota normal – u těchto vlastností se chová jako start.
  • Hodnota stretch – položky automatické velikosti v rozložení se roztáhnou.

Podpora v prohlížečích a implementace

Standardizátoři mají CSS grid Level 3 zatím rozpracovaný. V únoru 2022 byla tato skvělá nová věc podporovaná jen ve verzi Firefoxu Nightly. I tam je ale potřeba zapnout vlaječku layout.css.grid-template-masonry-value v about:config.

Řešit fallbacky bude v případě nativní implementace relativně snadné, protože máme podmínku podpory – @supports:

@supports (grid-template-rows: masonry) {
  .container {
    display: grid;
    grid-template-rows: masonry;
  }  
}

Je samozřejmě otázkou, jak může vypadat náhradní řešení z vizuálního pohledu.

Doufejme, že o těchto náhradních řešeních nebudeme muset dlouho přemýšlet a po připomínkovém řízení ke specifikaci dojde k implementaci v Chromu a odvozených prohlížečích a pak chvíli čekání na Safari, jak už to ve světě dnešního vývoje webů chodí.

Další možnosti, jak řešit masonry

Do doby, než se dokončí specifikace a prohlížeče nativní masonry implementují, přidávám sem také seznam alternativních metod.

Javascriptové pluginy Davida DeSandra

Existují dvě varianty:

  • Masonry
    „JavaScript Grid Layout library“ je použitelná s jQuery nebo také s čistým JavaScriptem. Má spoustu možností nastavení. 24 kB dat po minifikaci, 8 kB po gzipu. vrdl.in/mas
  • Colcade
    Jedna osmina velikosti Masonry. Na druhou stranu neumí některé funkce sesterské knihovny, jakými jsou třeba spojování sloupečků (multi-column-spanning) nebo přechody (transitions). vrdl.in/colca

Další metody alternativního řešení zděného layoutu mají dvě věci společné. Na rozdíl od DeSandrova pluginu nepotřebují JavaScript. A řeší vždy jen část scénářů, pro které zděný layout vývojáři používají.

Vícesloupcový layout

CSS Multi-column Layout je možné použít pro účely jednoduchého masonry:

.container {
  column-count: 4;
  column-gap: 10px;
}

Nevýhodou je to, že směr layoutu bude vždy po sloupcích, nikoliv po řádcích. Prohlížeč se také – kvůli povaze vícesloupcové sazby – nebude trápit tím, když poslední sloupec zůstane vyplněný jen z malé části.

CodePen: vrdl.in/y5b7l

CSS grid a zahuštěné umístění

Vlastnost grid-auto-flow může mít hodnotu dense, která zajistí, že prohlížeč může vyplnit mezery změnou pořadí prvků.

.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-flow: dense;
  gap: 10px;
}

Nevýhoda? Pořád jde o vykreslení do mřížky, takže mezi jednotlivými položkami většinou zůstávají nevyplněné mezery.

CodePen: vrdl.in/km26b

Flexbox, :nth-child a order

Tobias Ahlin Bjerrome se pokusil o řešení flexboxem, selektorem :nth-child(n) a vlastností order. vrdl.in/tobmas

/* Render items as columns */
.container {
  display: flex;
  flex-flow: column wrap;
}

/* Re-order items into rows */
.item:nth-child(3n+1) { order: 1; }
.item:nth-child(3n+2) { order: 2; }
.item:nth-child(3n)   { order: 3; }

/* Force new columns */
.container::before,
.container::after {
  content: "";
  flex-basis: 100%;
  width: 0;
  order: 2;
}

Je to plné dobrých nápadů, relativně dobře to funguje, ale ne ve všech rozlišeních. Navíc je složité to nastavovat pro různý počet sloupců v layoutu.

CodePen: vrdl.in/dghb6

Související

Pokud znáte další řešení, které pomůže ostatním čtenářkám a čtenářům, než prohlížeče začnou podporovat nativní variantu, neváhejte se ozvat v komentářích.