Flexbox layout

Flexbox: Layout budoucnosti

Celkový layout (rozložení) stránky se z historicky-technických důvodů dělá různě: tabulkou, plovoucímu prvky či JavaScriptem.

Moderní prohlížeče ale nabízejí jednu metodu (s gridem jsou vlastně dvě), která dokáže prvky na stránce uspořádat tak, aby si zachovali svůj vzhled a zároveň se přizpůsobily stránce.

Pokud vás jen zajímá princip Flexboxu, podívejte se na ukázku od Bennetta Feeleho. Přehledný seznam všech konfiguračních vlastností najdete v CSS Tricks průvodci. Popis vlastností a kódu najdete v druhé polovině článku.

Flexibilní layout

Flexbox lze použít jak na plovoucí seznamy (např. obrázků, zboží v obchodě, apod.) tak i na zobrazení hlavičky, patičky či postranního panelu na stránce (i když grid to zvládne ještě lépe).

Pro pochopení myšlenky Flexboxu je potřeba si nejprve ujasnit, jak se jednotlivé prvky chovají na stránce.

Textové prvky

Základní prvek stránky jsou textové (inline) prvky, které se vždy přizpůsobí svému (textovému) obsahu, takže se příliš nedá ovlivnit, jak budou velké (vyjma paddingu). Proto se pro navrhování designu příliš nehodí (kromě textu a prvků, které na něj mají nějak reagovat – například ikonky či emotikony uvnitř textu).

Textové prvky se vždy řadí zleva doprava (nebo opačně)

Bloky

Pro design nejčastěji používanými prvky jsou pravděpodobně bloky. U těch se dá určit šířka i výška a prvky si je zachovávají (kromě případu, kdy rozměr nastavíte na auto a pak se blok chová podobně jako textový prvek). Díky automatice a omezení rozměrů ({min|max}-{width|height}) lze dosáhnout i určité flexibility.

Bloky se vždy řadí pod sebe zhora dolu. Změny pořadí lze dosáhnout pouze absolutním pozicováním (např. tím že navigaci v HTML dáte na konec, aby nerozbíjela SEO, a pak ji absolutní pozicí přesunete do hlavičky stránky).

Bloky lze seřadit zleva doprava díky obtékání (nebo zprava doleva). To má ale svá omezení, protože není možné prvky řadit zleva doprava a přitom je mít na pravé straně (dosahuje se toho složitými kombinacemi vnořování bloků, marginů či paddingů a JavaScriptu).

Položky seznamu

Celkem málo používaný display:list-item se chová jako blok, ale navíc ještě bere v úvahu definici odrážek svého kontejneru.

Pro layouty není prakticky použitelný. Jediný důvod (kromě kompletnosti), proč ho zde uvádím je ten, že se chová podobně ke svému kontejneru jako se chová flex-item k Flexboxu a přebírá jeho specifické definice.

Tabulky

Tabulky jsou určeny pro data, ale často se používají i pro layout díky klíčovým vlastnostem řádek a sloupců.

Díky řádkám se dá zajistit to, že všechny prvky v řádce mají stejnou výšku, což je často potřeba pro postranní panely nebo tzv. sloupcový layout (kdy všechny sousedící bloky mají stejnou výšku). Toho není pomocí bloků možné dosáhnout, protože blok (při automatice) se vždy přizpůsobí obsahu.

Díky sloupcům, které musí vždy vyplnit celou šířku tabulky, se dá pak dosáhnout automatického responzivního zvětšování či zmenšování.

Díky spojování sloupců či řádek se pak dá dosáhnout různých propozic, kdy např. obsah stránky je vždy 3× větší než menu po straně nebo že postraní menu nezasahuje do hlavičky stránky.

Flexbox

Flexbox je vlastně moderní způsob, jak dosáhnout toho, čeho se již celá léta dosahuje různými kombinacemi výše uvedených vlastností.

První flexbox byl navržen v roce 2009 (display:box), následně byl upraven v roce 2011 (display:flexbox) a současná verze (display:flex) pochází z roku 2012 a do prohlížečů pronikala od srpna 2012 (Chrome) do března 2014 (Firefox). Dá se tedy říci, že Flexbox je skutečně moderní. (Zkuste demo pro porovnání podpory první a třetí verze Flexboxu.) Oproti tomu tabulkové layouty se používají od druhé poloviny 90. let (od nástupu Netscape a IE v roce 1995).

Jak již název napovídá, rozložení prvků v Flexboxu je flexibilní (česky pružné nebo přizpůsobivé). Základní pravidlo je, že není žádný přesně určený směr a pořadí, jak se budou prvky vykreslovat. Sám designer si může určit směr, kterým se mají prvky řadit (horizontálně či vertikálně, zleva, zprava, zeshora, zezdola). Navíc není pevné ani pořadí, a prvky lze přesouvat nezávisle na HTML definici.

Aby toho mohl Flexbox dosáhnout, musí se prvky chovat podobně jako plovoucí prvky a buňky tabulky. Pokud se tedy nevejdou do vymezeného prostoru, mohou se zalomit a vytvořit tak další řádek nebo sloupec (podle směru toku).

Navíc se mohou přizpůsobit tak, aby vyplnili zbývající prostor (podobně jako text-align:justify), přičemž berou v úvahu buď svůj obsah nebo definované rozměry. Designer navíc může určit, které prvky se mohou či nemohou zvětšovat a v jakém poměru vzhledem k ostatním.

A samozřejmě aby celá stránka nevypadala jako výstřižkový deníček puberťačky, druhý rozměr prvků je možno sjednotit tak, aby celé uskupení vypadalo úhledně.

Pokud nepoužijete automatický výpočet rozměrů, pak můžete naopak určit, jak se mají prvky zarovnávat (podobně jako u textu pomocí text-align a vertical-align).

Celé se to dá shrnout do následujících bodů:

  • směr toku prvků určuje designer (grafik)
  • pořadí prvků určuje CSS, nikoli HTML
  • pokud se prvky nevejdou, mohou se zalomit
  • prvky je možno přizpůsobit tak, aby vyplnily prostor
  • druhý rozměr prvků je možno sjednotit
  • je možno určovat zarovnání prvků

Použití Flexboxu

Jak už je zmíněno výše, Flexbox se v CSS definuje vlastností display. Pro Safari je potřeba použít prefix -webkit-!

Update: Safari od verze 9.0 podporuje flexbox v bezprefixové podobě display: flex.

Momentálně budu psát o nejnovější verzi, popis starších verzí je na konci článku.

.layout {
    display: -webkit-flex;
    display: flex;
}
.textLayout {
    display: -webkit-inline-flex;
    display: inline-flex;
}

Tím říkáte prohlížeči, že daný prvek se bude chovat jako Flexbox (třetí verze) a všechny jeho (přímí) potomci se budou chovat jako Flex-item (neexistuje žádná definice display:flex-item, prostě se předpokládá, že vše unitř Flexboxu je flex-item).

Navenek se flex chová stejně jako block a inline-flex jako inline (resp. inline-block). Fungují na něj tedy vlastnosti jako width, height, margin, atd. stejně jako na block resp. inline-block.

Směr a pořadí

Základní vlastností je směr toku, který určuje vlastnost flex-direction.

/* horizontální */
.left-to-right { flex-direction: row }
.right-to-left { flex-direction: row-reverse }
/* vertikální */
.top-to-bottom { flex-direction: column }
.bottom-to-top { flex-direction:
                         column-reverse }

Výchozí zarovnání je row. Direction má ještě tu vlastnost, že je závislá na směru toku textu, nadefinované směry (left-to-right) tedy platí pro klasický (západní) text; v (asijském) prostředí, kde se čte zprava a/nebo zespodu, budou mít hodnoty opačný význam (není tedy vhodné používat Flexbox pro skládání velkého obrázku, jak se to používá třeba v emailech, protože by se mohli zpřeházet).

Se směrem toku souvisí i pořadí prvků. To se ve výchozím stavu drží HTML definice, ale lze ji libovolně měnit:

.layout > *    { order: 5 }
.top-priority  { order: 1 }
.high-priority { order: 2 }
.low-priority  { order: 8 }
.first         { order: -1; }
.last          { order: 999; }

Prvky se pak řadí podle velikosti (čísla order), přičemž row a column zobrazí jako první položku s nejnižším číslem a *-reverse naopak s nejvyšším číslem na začátku. Pokud má více prvků stejné pořadí, pak se řadí podle pořadí v HTML (samozřejmě při opačném řazení se i pořadí podle HTML otočí).

Díky tomu můžete například změnit pořadí v layoutu, kdy přesun sidebaru zleva doprava provedete jen změnou order v CSS (a není tak potřeba generovat nové HTML), nebo různé navigační prvky umístíte na konec stránky a pak je pomocí CSS vložíte na ta správná místo do textu (mezi odstavce).

Poslední vlastnost, která ovlivňuje tok prvků, je zalamování (wrap) řádek či sloupců. Díky ní můžete nejen zalamování zapnout a vypnout, ale také může ovlivnit, jakým směrem se bude zalamování provádět a tím ovlivnit druhý směr toku:

/* vždy přizpůsob do 1 řádku */
.layout.one-row { flex-wrap: nowrap }
/* pokud se nevejdou, zalom na nový řádek */
.layout.top-to-bottom { flex-wrap: wrap }
.layout.bottom-to-top {
                flex-wrap: wrap-reverse }

Kombinací všech vlastností můžete přesně určit odkud kam se budou prvky ubírat. Zkombinovat to můžete do vlastnosti flex-flow.

/* tok zprava doleva zespoda nahoru */
.layout-rows-right-bottom {
   display: flex;
   flex-direction: row-reverse;
                      /*zprava doleva*/
   flex-wrap: wrap-reverse;
                      /*zespoda nahoru*/
}
/* alternativně: */
.layout-rows-right-bottom {
   display: flex;
   flex-flow: row-reverse wrap-reverse;
}
/* sloupce zprava doleva zespodu nahoru */
.layout-columns-right-bottom {
   display: flex;
   flex-flow: column-reverse wrap-reverse;
}

Rozměry

Velikost flex-item určuje několik vlastností. Za prvé jsou to klasické vlastnosti width a height.

/* obrázek vždy stejný nezávisle na směru
    toku a velikosti okna */
.layout > img {
    width: 200px;
    height: 200px
}

/* klasický odstavec
    co se přizpůsobí textu */
.layout > p {
    width: 100%;
    height: auto;
}

Ale vzhledem k tomu, že pomocí row a column můžete snadno změnit směr toku prvků, není příliš vhodné určovat rozměry jako šířku a výšku. Existuje lepší, k tomu přímo určená, vlastnost, která definuje základní rozměr (basic size nebo basis) prvku ve směru toku. Ten se pak automaticky aplikuje na rozměr, který je potřeba změnit pro rozložení prvků v layoutu (a má vyšší prioritu než width a height):

/* obrázek 200x200px;
   ve Flexboxu bude minimální rozměr 180px
   (a dopočte se podle zbylého místa)
*/
.layout > img {
    width: 200px; height: 200px;
    flex-basis: 180px;
}

Následně se v úvahu berou vlastnosti pro poměr růstu (grow) a zmenšování (shrink) jednotlivých prvků. Nula říká, že daný prvek se měnit nesmí a tudíž nula u růstu znamená, že prvek nesmí být větší než zadaný rozměr a nula u smrkávání naopak říká, že prvek se nesmí zmenšit pod zadanou velikost. Pokud je tedy grow i shrink nastaveno na 0, zůstává flex-item stejně velký nezávisle na ostatních vlastnostech FlexBoxu (stejně jako klasický blokový prvek).

Větší čísla pak určují poměr, ve kterém budou prvky růst nebo se zmenšovat. Pokud tedy tři prvky budou mít poměr 1:3:2, prohlížeč volný prostor vydělí 6 (1 + 3 + 2) a rozměry připočte k základním rozměrům (basis) jednotlivým prvků – prostřední prvek tedy bude mít rozměr {výchozí rozměr prvku + ((rozměr rodiče – součet(výchozí rozměr všech prvků)) / 6 * 3)}. Obdobně, pokud se prvky nevejdou, bude se stejným principem jejich rozměr zmenšovat.

.layout > * {
            flex-grow: 1; flex-shrink: 1; }
.fix-size { flex-grow: 0; flex-shrink: 0; }
.double-size { flex-grow: 2 }
.unimporant  { flex-shrink: 3 }
            /* zmenší se trojnásobně */

Pozor na to, že výchozí hodnota flex-grow a flex-shrink je v různých prohlížečích různá. Je tedy dobré si výchozí hodnoty vždy nadefinovat v CSS.

Všechny tyto hodnoty ovlivňující velikost můžete sjednotit do základní vlastnosti ve formátu flex: grow shrink basis:

/* obrázek 200x200px;
   ve Flexboxu bude minimální rozměr 180px
   přičemž se může zvětšit,
   ale nesmí být menší
*/
.layout > img {
    width: 200px; height: 200px;
    flex: 1 0 180px;
}

Rozměr ještě samozřejmě ovlivňují vlastnosti pro minimální a maximální velikost, které pak omezují růst (flex-grow vs. max-*) a zmenšování (flex-shrink vs. min-*):

/* obrázek 200x200px;
   ve Flexboxu bude minimální rozměr 180px
   smí se zvětšit, ale ne víc než na 220px
*/
.layout > img {
    width: 200px; height: 200px;
    flex: 1 0 180px;
    max-width: 220px
}

Pokud by prvek zvětšením nebo zmenšením přesáhl svou minimální nebo maximální velikost, zbylá velikost se přerozdělí mezi zbývající prvky. Pokud již (v dané řádce či sloupci) neexistuje žádný prvek, který se může příslušně zvětšit či zmenšit, zůstane místo nevyužito (viz kapitola Zarovnání).

Výchozí velikost lze samozřejmě zadat i v procentech, kdy se jako 100% bere celkový rozměr Flexboxu.

Pokud mají ale být všechny prvky stejně velké, není potřeba počítat jejich poměr (např. 33,33% pro 3 prvky), ale stačí zadat:

menu-item { flex: 0 1 100%; }
/* alterativní zápis: */
menu-item { flex: 1 1 1px; }

První hodnota pro růst se bude ignorovat, protože více než 100% prvek stejně mít nebude (i kdyby byl sám). Druhá pak říká, že se mají všechny prvky zmenšit ve stejném poměru. K tomu dojde v případě, že obsah všechny prvků se po zmenšení vejde. Pokud se ale nějaký rozměr nevejde, prohlížeč upraví poměr tak, aby se obsah vešel.

Druhý zápis s pixely bude mít samozřejmě stejný výsledek, jen s tím rozdílem, že se prvky budou naopak ve stejném poměru zvětšovat.

Pokud chcete mít dva prvky v poměru 1:2, nemusíte počítat 33% a 66%, ale stačí jeden z těchto zápisů:

menu-item { flex: 0 1 100%; }
big-item { flex: 0 1 200%; }

menu-item { flex: 1 1 1px; }
big-item { flex: 2 1 1px; }

V tomto případě bude druhá položka dvakrát tak velká jako ta první. Navíc tento zápis funguje i v případě, že do flexboxu přibude další prvek. Pak se automaticky přepočtou rozměry s tím, že větší prvek stále bude zabírat dvakrát tolik místa než ostatní (tedy v případě 3 prvků to bude 50%).

Zarovnání

Pokud správně nastavíte vlastnosti grow a shrink (a nepoužijete min-* a max-* rozměry), budou prvky vždy vyplňovat celý prostor (na šířku nebo na výšku podle toku). Ještě ale zbývá druhý rozměr, který může být stejně důležitý. Pro jeho nastavení slouží několiv vlastností.

První vlastností je justify-content, která začne platit v případě, že je zakázáno flex-grow a prvky nevyplňují celou řádku či sloupec.

Poznámka: v případě, že je zakázáno flex-shrink a prvky se do řádky nevejdou, začne se Flexbox chovat jako klasický blok a v závisloti na overflow zobrazí posuvníky nebo prvky přetečou nebo zmizí.

.layout.left { justify-content: flex-start }
.layout.right { justify-content: flex-end }
.layout.center { justify-content: center }
.layout.spaced {
            justify-content: space-between }
.layout.equaled {
             justify-content: space-around }

Center je snad jasný („na střed“ stejně jako text) a hodnoty flex-start and flex-end odpovídají zarovnání vlevo a vpravo (u textu), avšak opět závisí na směru toku; pro row (při čtení zleva doprava) bude flex-start znamenat „doleva“ zatímco pro row-reverse naopak „doprava“ (a pro column pak „nahoru“ resp. „dolu“).

Poslední dvě hodnoty odpovídají textovému text-align:justify, přičemž rozdíl je v tom, že space-between („místo mezi“) vkládá mezery jen mezi prvky a první a poslední prvek jsou zarovnány k okrajům, zatímco space-around („místo okolo“) vloží mezery i před první a za poslední prvek.

Další vlastnosti jsou align-items a align-content, které s hodnotou stretch zajistí, že všechny flex-item budou mít stejný rozměr.

.layout {
    align-items: stretch;
    align-content: stretch;
}

Vlastnost align-items:stretch platí v případě, že jsou všechy prvky v jedné řádce/sloupci, align-content:stretch platí v případě, že došlo k zalomení (wrap).

Není ale potřeba nechávat prvky zvětšovat a je možno je nechat tak velké, jak by byly v jiném layoutu. Pak se dá těmito vlastnostmi určit, kam se mají zarovnat:

.layout.align-top {
                   align-items: flex-start }
.layout.align-bottom {
                     align-items: flex-end }
.layout.align-center { align-items: center }
.layout.align-text { align-items: baseline }

.layout.lines-top {
                 align-content: flex-start }
.layout.lines-bottom {
                   align-content: flex-end }
.layout.lines-center {
                     align-content: center }
.layout.l-spaced {
              align-content: space-between }
.layout.l-equaled {
               align-content: space-around }

Všechny hodnoty již byly popsány výše kromě hodnoty baseline, která zarovná pvky podle spodního okraje jejich textu – prvky s méně řádky tedy budou posunuty dolu tak, aby se zarovnaly s pvkem s nejvíce řádky textu (při tom se samozřejmě ignoruje jakýkoliv padding a margin prvků a naopak se bere v úvahu font-size a line-height).

Nastavení align-items platí pro všechny prvky (v dané řádce), vlastnost align-content se použije jen v případě, že došlo k zalomení – nemá tedy cenu kombinovat flex-wrap:nowrap a align-content z toho důvodu, že když je řádka jen jedna, je stejně vysoká jako celý flexbox a tudíž ji nelze zarovnat.

Pro zarovnání slouží ještě jedna vlastnost align-self, která se aplikuje na flex-item (na rozdíl od výše uvedených, které platí pro samotný Flexbox). Funguje stejně jen s tím rozdílem, že má vyšší prioritu než výše uvedené vlastnosti a dá se tak použít pro přepsání výchozího zarovnání:

.layout { align-items: center; }
.layout > .top-item {
                 align-self: flex-start; }
.layout > .bottom-item {
                   align-self: flex-end; }

Označené položky pak budou jednoduše „vyskakovat“ z jednotného layoutu (jak to použijete je je na vás).

Zarovnání – rekapitulace

Ještě jednou podle článku Patricka Brosseta ujasnění, jak přesně fungují vlastnosti pro zarovnání:

Vlastnosti začínající justify-* zarovnají prvky v primárním směru – můžete si to pamatovat tak, že ve Wordu a podobných programech zarovnání Justify vyrovná text v řádce, tedy v primárním směru, kterým se běžný text ubírá.

Naopak vlastnosti začínající align-* vyrovnají prvky v opačném směru – jednoduchou vylučovací metodou „když to není justify, musí to být align„.

Z druhého konce, vlastnosti končící *-self zarovnávají konkrétní prvek (self znamená „já“ nebo „být sám sebou“) a určují, jak bude prvek zarovnán uvnitř svého rodiče, podobně jako margin. Jak je v CSS zvykem, vlastnost nastavená přímo prvku má vyšší prioritu než zděděné vlastnosti.

Vlastnosti končící *-content naopak zarovnávají obsah prvku (content = „obsah“) z čehož vyplývá, že se aplikují na kontejner a zarovnávají jeho potomky. Jelikož jde ale o vlastnost kontejneru, fungují podobně jako padding a nepřenáší se na konkrétní prvky.

Nakonec, vlastnosti končící *-items se nastavují na kontejneru, který dané prvky vlastností (items = „položky“), ale definice se pomocí dědění (inheritance) přenáší na konkrétní položky. To, že se *-items přenáší na potomky, si můžete pamatovat podle toho, že items je v angličtině množné číslo a tudíž se vztahuje na více prvků (tedy potomky) a nikoliv na kontejner, který je vždy jen jeden.

Co nefunguje
(nebo by se nemělo používat)

  • Vlastnost display nenastavujte pro flex-item (prohlížeč by sám měl použít definici flex > * { display: flex-item }).
    • Pokud display nastavíte (na nějakou speciální hodnotu – např. table-cell), nemusí Flexbox fungovat správně.
    • Jako bezpečné se jeví pouze hodnoty block, inline, flex (vnořený layout) a samozřejmě none pro skrytí prvku.
    • IE10 (tweener) má problémy i s inline flex-itemy (span, a, apod.) prvky a neaplikuje na ně některé vlastnosti (např. order). Pokud potřebujete podporu flexboxu i v IE10, nastavte .layout > * { display:block }.
    • Nedoporučuje se ani nastavování visibility pro flex-item, protože některé prohlížeče to špatně snášejí (čti obsahují bugy).
  • Použití paddingu na Flexbox nebo marginu na flex-item může způsobit problémy v kombinaci s flex-grow, flex-shrink nebo align-*.
  • Vlastnosti float a clear nemají vliv na flex-item; směr toku řídí vlastnosti flex-direction a flex-wrap.
  • Vlastnost text-align a vertical-align nefungují na flex-item; zarovnání řídí justify-content, align-items a align-content. Avšak na text uvnitř flex-item tyto vlastnosti fungují normálně (vč. dědění od Flexboxu).
  • Nedoporučuje se vkládat text přímo do Flexboxu; prohlížeč by sice z něj měl vytvořit flex-item, ale není jisté, jak se k němu zachová (hlavně v kombinaci různých align-* a *-align).
    • Vždy text obalte DIVem nebo SPANem, který bude moci prohlížeč použít jako flex-item.
  • Hodnoty order slouží pouze pro grafické uspořádání a nijak nemění ostatní vlastnosti – např. šipky a tabulátor mohou přesouvat focus na jiný prvek než ten, který čekáte ve Flexboxu.
    • Stejně tak nemusí být splněna Přístupnost (Accessibility) pokud změníte pořadí prvků, které obsahují nějaké důležité informace (např. seřadit výherce jen pomocí CSS není dobré, protože čtečka pro nevidomé to nepochopí!) – zde lze použít ARIA atribut aria-flowto pro určení dalšího prvku.
.layout > div { display: table-cell }
              /* opravdu špatný nápad!!! */

.layout {
    align-content: flex-start;
                      /*pro flex-item */
    vertical-align: bottom;
                   /* pro text uvnitř */
}

Starý, nový a tweener

Jak už jsem psal výše, existují 3 verze Flexboxu (box, flexbox a flex), nejčastěji se ale setkáte s označením nový (tj. aktuální, třetí verze) a starý (první verze). Druhá verze platila jen rok a tak má minimální podporu jen v konkrétních verzích prohlížečů (prakticky jen v IE10, kde se jí říká tweener). Navíc novější prohlížeče podporují všechny verze díky tomu, že používají různé definice.

.layout {
  /* první "stará" verze (2009) */
  -ms-box-orient: horizontal; /* IE10 */
  display: -webkit-box;
                /* iOS 6+, Safari 3.1+ */
  display: -moz-box; /* Firefox 4 - 19 */
  display: box; /* ostatní (Opera 12-14) */
  /* druhá "tweener" verze (2011) */
  display: -ms-flexbox; /* IE10 */
  display: flexbox; /* ostatní prohlížeče */
  /* třetí "nová" verze (2013) */
  display: -moz-flex; /* Firefox 20 - 21 */
  display: -webkit-flex;
                  /* iOS 7.1+, Safari 6+ */
  display: flex; /* ostatní prohlížeče
               (Firefox 22+, Chrome 21+,
             IE11, Opera 15+, Safari 9+) */
}

Důležité je zachovat toto pořadí definice, abyste nenutili nový prohlížeč používat starou verzi.

Poznámka: Firefox 20 – 27 podporuje zápis nové verze, ale pouze je mapuje na starou, takže ignoruje vše, co stará verze neumí.
Plná podpora nového Flexboxu je až od verze Firefox 28.
Prefixovaný zápis -moz-flex (FF 20 a 21) tedy můžete klidně ignorovat, protože nic nového nepřináší.

Tímto získáte podporu pro stejně vysoké sloupce ve většině současných prohlížečů s výjimkou IE9 a starší (pro něž nejspíše dopisujete i jiné věci) a Opera starší než 12.1 (což je minimum uživatelů).

Pokud potřebujete podporu i do starších prohlížečů, můžete zkusit polyfill framework Flexie, který používá neprefixovaný zápis staré verze a přidává podporu do IE 6 – 9 a Opery 10 – 12. Pozor ale na to, že Flexie nepřidává polyfill pro nic jiného, takže např. vlastnosti nastavené selektorům, které daný prohlížeč nativně nepodporuje, nebudou fungovat tak jako tak (takže nejlépe používejte ID nebo class pro definici Flexboxu). Případně si můžete zkusit pohrát s jeho mladším bratříčkem reflexie, který toho umí víc, ale není doladěný (a pravděpodobně to již autor neplánuje). Praktické testy ale ukazují, že to funguje jen na jednoduché případy. V trochu složitějším buď končí chybou nebo špatným formátováním.

Starý Flexbox lze také použít pro změnu pořadí, které má také své specifické definice:

.first {
  /* starý */
  -webkit-box-ordinal-group: 1; /* iOS 6+ */
  -moz-box-ordinal-group: 1;      /* FF19 */
  -ms-flex-order: 1;              /* IE10 */
  box-ordinal-group: 1;        /* ostatní */

  /* tweener */
  -ms-flex-order: 1;
  flex-order: 1;

  /* nový */
  -webkit-order: 1;          /* Safari 6+ */
  order: 1;                    /* ostatní */
}

Trochu problémy může dělat experimentální podpora ve Firefoxu 4 – 19, které špatně počítají rozměry přehozených prvků. Pozor na to, že Flexie musí prvky fyzicky přeházet v DOMu, takže pak nemusí správně fungovat některé CSS nebo JS selektory.

Starý Flexbox samozřejmě podporuje i předchůdce flex-grow v podobě vlastnosti box-flex:

.layout > .grow {
  -webkit-box-flex: 1;
  -moz-box-flex: 1;
  box-flex: 1;
}
.layout > .grow-double {
  -webkit-box-flex: 2;
  -moz-box-flex: 2;
  box-flex: 2;
}
.layout > .fixed {
  -webkit-box-flex: 0;
  -moz-box-flex: 0;
  box-flex: 0;
}

Tweener řeší zvětšování a zmenšování stejně jako nová verze, ale místo specifické vlastnosti flex používá funkci flex(), kterou nastavíte do width nebo height (na rozdíl od nové verze tak umožňoval zvětšovat či zmenšovat různě pro row a column; ale to se dá snadno obejít přes třídy).

.layout > * {
    /* tweener */
    width: -ms-flex(1 1 auto);
    height: -ms-flex(1 1 auto);
    width: flex(1 1 auto);
    height: flex(1 1 auto);
}
/* obrázek 100x200px bez zvětšování */
.layout > * {
    /* pro ostatní verze */
    width: 200px;
    height: 100px;
    /* pro tweener */
    width: -ms-flex(0 1 200px);
    height: -ms-flex(0 1 100px);
    width: flex(0 1 200px);
    height: flex(0 1 100px);
}

Pro tweener byste správně měli používat všechny druhy prefixů, ale jelikož jediná použitelní implementace je v IE10, postačí použít prefix -ms-.

Všechny verze také podporují flex-direction, i když v jinak uspořádané definici:

/* tok řádek zprava doleva */
.layout-rows-reverse {
   /* stará verze */
   display: -webkit-box;
   display: -moz-box;
   display: box;
   -webkit-box-orient: horizontal;
   -moz-box-orient: horizontal;
   box-orient: horizontal;
   -webkit-box-direction: reverse;
   -moz-box-direction: reverse;
   box-direction: reverse;

   /* nová verze */
   display: flex;
   -ms-flex-direction: row-reverse;
                            /* tweener */
   flex-direction: row-reverse;
}

/* sloupce zeshora dolu */
.layout-columns-top {
   /* stará verze */
   display: -webkit-box;
   display: -moz-box;
   display: box;
   -webkit-box-orient: vertical;
   -moz-box-orient: vertical;
   box-orient: vertical;
   -webkit-box-direction: normal;
   -moz-box-direction: normal;
   box-direction: normal;

   /* nová verze */
   display: flex;
   -ms-flex-direction: column; /* tweener */
   flex-direction: column;
}

Zalamování ani zmenšování stará verze nepodporuje, takže v případě, že se prvky nevejdou, vytečou ven z kontejneru.

Podporuje ale jednoduchou verzi zarovnání a roztažení:

.layout > * {
   /* roztažený v druhém rozměru */
   -webkit-box-align: stretch;
   -moz-box-align: stretch;
   box-align: stretch;
   /* další možnost pro zarovnání:
         start, end, center */
   /* některé prohlížeče podporují
                               i baseline */

   /* tweener */
   -ms-flex-align: stretch;
   flex-align: stretch;
   /* podporuje vše ze staré verze
                               i baseline */

   /* zarovnání pokud je vypnuto box-flex */
   -webkit-box-pack: start;
   -moz-box-pack: start;
   box-pack: start;
   /* další možnost: end, center, justify */
   /* justify funguje jako space-between */

   /* tweener */
   -ms-flex-pack: start;
   flex-pack: start;
   /* podporuje vše ze staré verze */
}

Tweener (IE10) podporuje i zalamování řádek:

.layout {
   /* tweener */
   display: -ms-flexbox;
   /* všechny hodnoty odpovídají
                              nové verzi: */
   -ms-flex-direction: row;
   -ms-flex-wrap: wrap;
   -ms-flex-line-pack: start;
              /* zarovnání pro více řádek */
}
/* zkráceně */
.layout.backward {
   /* tweener */
   -ms-flex-flow:
               column-reverse wrap-reverse;
   -ms-flex-line-pack: end;
}

Podrobnější popis tweener syntaxe najdete ve specifikaci, nezapomeňte ale, že nikdy nebyla dokončena a tak je potřeba ověřit, co skutečně funguje a co bylo jen přání autorů.

Také si dejte pozor, že pokud budete tweener definice testovat v IE11 pomocí emulace (F12), IE bude sice používat k vykreslování jádro IE10, ale debugger bude překládat i definice z nové verze. Pro správné otestování je tedy potřeba odšktnout všechny definice určené pro novou verzi a nechat jen ty pro tweener (ty s prefixem -ms-).

Rekapitulace

Pro přehlednost ještě jednou všechny možnosti se všemi styly pro zpětnou kompatibilitu. Prohlížeče starší než z roku 2009, které nepodporují žádnou verzi flexbox nejsou zde řešeny.

Kódy budou vždy rozděleny na dvě části: první je pro prohlížeče vydané mezi lety 2009 a 2013 (t.j. iOS6, Safari 3.1, Firefox 4+, Opera 12+) a druhý pro IE10+ (-ms-*), iOS 7+ (-webkit-*), a ostatní prohlížeče vydané po roce 2013 (IE11+, Firefox 22+, Chrome 21+, Opera 15+). Pokud vám tedy stačí jen podpora používaných prohlížečů, stačí použít jen druhou část. Pokud kód není rozdělen, není daná část podporována ve starších verzích.

Zapnutí flexboxu

.flexbox, .flexbox > .flexbox {
    display: -webkit-box;
    display: -moz-box;
    display: box;

    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}

Tok položek

Řádky se zalamováním

Pokud se všechny položky nevejdou do jedné řádky, budou se další řádky vytvářet směrem dolu, takže první položka bude v nejvyšším řádku a poslední v nejnižším.

.flex-rows-wrap {
        -ms-flex-direction: row;
        -ms-flex-wrap: wrap;
	-webkit-flex-direction: row;
        -webkit-flex-wrap: wrap;
	flex-direction: row;
        flex-wrap: wrap;
}

Řádky bez zalamování

.flex-row-nowrap {
	-webkit-box-orient: horizontal;
	-moz-box-orient: horizontal;
	box-orient: horizontal;
	-webkit-box-direction: normal;
	-moz-box-direction: normal;
	box-direction: normal;

        -ms-flex-direction: row;
        -ms-flex-wrap: nowrap;
	-webkit-flex-direction: row;
        -webkit-flex-wrap: nowrap;
	flex-direction: row;
        flex-wrap: nowrap;
}

Sloupce se zalamováním

Sloupce se budou vytvářet ve směru čtení textu (tedy např. zleva doprava v Evropě nebo zprava doleva v Asii).

.flex-columns-wrap {
        -ms-flex-direction: column;
        -ms-flex-wrap: wrap;
	-webkit-flex-direction: column;
        -webkit-flex-wrap: wrap;
	flex-direction: column;
        flex-wrap: wrap;
}

Sloupce bez zalamování

.flex-column-nowrap {
	-webkit-box-orient: vertical;
	-moz-box-orient: vertical;
	box-orient: vertical;
	-webkit-box-direction: normal;
	-moz-box-direction: normal;
	box-direction: normal;

        -ms-flex-direction: column;
        -ms-flex-wrap: nowrap;
	-webkit-flex-direction: column;
        -webkit-flex-wrap: nowrap;
	flex-direction: column;
        flex-wrap: nowrap;
}

Řádky s převráceným pořadím

Převrácené pořadí znamená, že pokud je text nastaven na čtení zleva doprava, budou se položky řadit zprava doleva.

.flex-row-reverse {
	-webkit-box-orient: horizontal;
	-moz-box-orient: horizontal;
	box-orient: horizontal;
	-webkit-box-direction: reverse;
	-moz-box-direction: reverse;
	box-direction: reverse;

	-ms-flex-direction: row-reverse;
	-webkit-flex-direction: row-reverse;
	flex-direction: row-reverse;
}

Sloupce s převráceným pořadím

Převrácené pořadí znamená, že pokud je text nastaven na čtení zleva doprava, budou se položky řadit zdola nahoru.

.flex-column-reverse {
	-webkit-box-orient: vertical;
	-moz-box-orient: vertical;
	box-orient: vertical;
	-webkit-box-direction: reverse;
	-moz-box-direction: reverse;
	box-direction: reverse;

	-ms-flex-direction: column-reverse;
	-webkit-flex-direction: column-reverse;
	flex-direction: column-reverse;
}

Obrácené zalamování

Pokud se všechny položky nevejdou do jedné řádky, budou se další řádky vytvářet směrem nahoru, takže první položka bude v nejnižším řádku a poslední v nejvyšším. Sloupce se budou vytvářet proti směru čtení (tedy směrem doleva při čtení zleva doprava).

.flex-reverse-wrap {
    -ms-flex-wrap: wrap-reverse;
    -webkit-flex-wrap: wrap-reverse;
    flex-wrap: wrap-reverse;
}

Zvětšování, zmenšování nebo zarovnání

Povolit zvětšování položek

Hodnotu 1 nahraďte za požadovanou úroveň růstu vzhledem k ostatním položkám.

.flex-item-grow {
	-webkit-box-flex: 1;
	-moz-box-flex: 1;
	box-flex: 1;

	-webkit-flex-grow: 1;
	flex-grow: 1;
}

Zakázat zvětšování položek

.flex-item-nogrow {
	-webkit-box-flex: 0;
	-moz-box-flex: 0;
	box-flex: 0;

	-webkit-flex-grow: 0;
	flex-grow: 0;
}

Povolit zmenšování položek

Hodnotu 1 nahraďte za požadovanou úroveň zmenšování vzhledem k ostatním položkám.

.flex-item-shrink {
	-webkit-flex-shrink: 1;
	flex-shrink: 1;
}

Zakázat zmenšování položek

.flex-item-noshrink {
	-webkit-flex-shrink: 0;
	flex-shrink: 0;
}

Zarovnání doleva a nahoru

Pokud jste položkám zakázali růst (grow:0), můžete je zarovnat doleva nebo nahoru.

.flexbox.flex-top,
.flexbox.flex-left {
	-webkit-box-pack: start;
	moz-box-pack: start;
	box-pack: start;

	-ms-flex-pack: start;
	-webkit-justify-content: flex-start;
	justify-content: flex-start;
}

Zarovnání doprava a dolu

Pokud jste položkám zakázali růst (grow:0), můžete je zarovnat doprava nebo dolu.

.flexbox.flex-bottom,
.flexbox.flex-right {
	-webkit-box-pack: end;
	moz-box-pack: end;
	box-pack: end;

	-ms-flex-pack: end;
	-webkit-justify-content: flex-end;
	justify-content: flex-end;
}

Zarovnání na střed

Pokud jste položkám zakázali růst (grow:0), můžete je zarovnat na střed.

.flexbox.flex-center {
	-webkit-box-pack: center;
	moz-box-pack: center;
	box-pack: center;

	-ms-flex-pack: center;
	-webkit-justify-content: center;
	justify-content: center;
}

Rovnoměrné zarovnání

Pokud jste položkám zakázali růst (grow:0), můžete je zarovnat tak, aby mezi nimi byly stejně široké mezery.

.flexbox.flex-justify {
	-webkit-box-pack: justify;
	moz-box-pack: justify;
	box-pack: justify;

	-ms-flex-pack: justify;
	-webkit-justify-content: space-between;
	justify-content: space-between;
}

Rovnoměrné rozložení

Pokud jste položkám zakázali růst (grow:0), můžete je zarovnat tak, aby mezi nimi i okolo nich byly stejně široké mezery. Podporováno je to jen v nejnovějších prohlížečích.

.flexbox.flex-even {
	-webkit-justify-content: space-around;
	justify-content: space-around;
}

Pořadí položky

Hodnotu 1 nahraďte za požadované pořadí položky. Hodnota může být i záporná

.flex-item-first {
	-webkit-box-ordinal-group: 1;
	-moz-box-ordinal-group: 1;
	box-ordinal-group: 1;
	flex-order: 1;

	-ms-flex-order: 1;
	-webkit-order: 1;
	order: 1;
}

Vzájemné zarovnání položek

Roztahování položek

Ve výchozím stylu se všechny položky nastaví na stejnou výšku (v řádce) nebo šířku (ve sloupci). Nastavit tento styl má smysl jen pokud potřebujete přepsat dříve definované zarovnání.

.flex-stretch {
    -webkit-box-align: stretch;
    -moz-box-align: stretch;
    box-align: stretch;

    -webkit-align-items: stretch;
    -webkit-align-content: stretch;
    align-items: stretch;
    align-content: stretch;
}

Vzájemné zarovnání doleva a nahoru

Ve výchozím stavu se všechny položky nastaví na stejnou výšku nebo šířku. Pokud to není žádoucí, můžete je nechat zarovnat doleva nebo nahoru.

Pro rekapitulaci, vlastnost align-items platí v případě, že jsou všechy prvky v jedné řádce/sloupci, align-content platí v případě, že došlo k zalomení (wrap).

.flexbox.flex-cross-top,
.flexbox.flex-cross-left {
	-webkit-box-align: start;
	-moz-box-align: start;
	box-align: start;

	-ms-flex-align: start;
	-webkit-align-items: flex-start;
	-webkit-align-content: flex-start;
	align-items: flex-start;
	align-content: flex-start;
}

Vzájemné zarovnání doprava a dolu

Ve výchozím stavu se všechny položky nastaví na stejnou výšku nebo šířku. Pokud to není žádoucí, můžete je nechat zarovnat doprava nebo dolu.

.flexbox.flex-cross-bottom,
.flexbox.flex-cross-right {
	-webkit-box-align: end;
	-moz-box-align: end;
	box-align: end;

	-ms-flex-align: end;
	-webkit-align-items: flex-end;
	-webkit-align-content: flex-end;
	align-items: flex-end;
	align-content: flex-end;
}

Vzájemné zarovnání na střed

Ve výchozím stavu se všechny položky nastaví na stejnou výšku nebo šířku. Pokud to není žádoucí, můžete je nechat zarovnat na střed.

.flexbox.flex-cross-center {
	-webkit-box-align: center;
	-moz-box-align: center;
	box-align: center;

	-ms-flex-align: center;
	-webkit-align-items: center;
	-webkit-align-content: center;
	align-items: center;
	align-content: center;
}

Skrolování obsahu uvnitř flexboxu

Základní vlastnost flexboxu je, že se automaticky přizpůsobí svému obsahu. Což je problém, pokud chcete mít uvnitř flexboxu kontejner obsahující více položek, které chcete, aby se skrolovaly.

<section> <!-- flexbox pro vyplnění stránky -->
    <h1>Nadpis</h1>
    <article>
        <p>...<p>...<p>...dlouhý skrolovaný obsah?
    </article>
</section>

Dosáhnout toho lze celkem snadno pomocí správného nastavení overflow na jednotlivé prvky:

section {
    height: 100vh; //vyplnění stránky
    display: flex;
    flex-flow: column nowrap;
    overflow: hidden; //vynucení pevného layoutu

}
article {
    overflow: auto; //zapnutí skrolování
}

Pokud vypnete skrolování (overflow) pro kontejner, který má flexbox, vynutíte tím pevný layout – tedy flexbox nebude brát ohled na obsah jednotlivých prvků uvnitř. Zapnutím skrolování na konkrétním vnořeném prvku umožníte jeho skrolování v rámci prostoru přiděleného flexboxem.

V závislosti na tom, kolik flexboxů nebo jiných kontejnerů máte v sobě, budete možná muset overflow: hidden nastavit více rodičům, dokud prohlížeč správně nevypočte velikost skrolované oblasti.

//Žádné skrolování ve stránce...
body, main, section { overflow: hidden; }
//...kromě tohohle prvku
body > main > section > article { overflow: auto; }

Obecně by nemělo být potřeba nastavovat overflow: hidden na úplně všechny prvky vč. BODY, ale záleží na tom, jak máte layout vytvořený – je potřeba vyzkoušet na konkrétním layoutu a postupovat od skrolovaného prvku nahoru, dokud se nezačne skrolovat.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Tato stránka používá Akismet k omezení spamu. Podívejte se, jak vaše data z komentářů zpracováváme..