Kvantitativní dotazy pro CSS

28. července 2015

Taky nesnášíte dokumentární filmy, které slibují kdesi cosi, a skutek utek? Mívají lákavé názvy jako Hledání obrovitého krakena, dráždí kalnými podvodními snímky a vzrušenými vědci, kteří ukazují kamsi daleko na oceán. Rozhodnete se, že se tedy na to podíváte, přesto ve vás trochu hlodá podezření. “Jestli neuvidím opravdu pořádně velkého kalmara, fakticky už jim napíšu dopis, který si nedají za rámeček.”

A jak se dalo čekat, po půldruhé hodině rozhovorů s nudnými rybáři je moderátor nucen konstatovat: “Ne… bohužel se nám nepodařilo najít žádného obřího hlavonožce. Snad uspějeme někdy příště [podmalováno majestátním orchestrálním finále].” Skvělé. Očekávali jste Našli jsme Nema, místo toho jste sledovali Nenašli jsme Nema.

Přátelé, já na vás takovou habaďůru hrát nebudu. Tohle je příručka, jak vytvářet stylové breakpointy pro kvantity HTML elementů, v mnohém podobně, jak už činíte s mediálními dotazy @media pro rozměry viewportu. Nebudu se odvolávat ani na nějakou rozostřenou specifikaci v dálavách, ani na zářící oči implementátora. Uděláme to dnes, s CSS, který už je k dispozici.

Dynamický obsah

Responzivní webový design se především zabývá jednou proměnnou: prostorem. Když testujeme responzivní layouty, vezmeme nějaké množství obsahu a díváme se, do jakého prostoru se úspěšně srovná. Myšlenou konstantou je přitom obsah; proměnnou je prostor.

Oblíbencem responzivního webového designu je dotaz @media, protože umožňuje vkládat breakpointy vždy, když jedna layoutová strategie přestává být životaschopná, a měla by proto uspět jiná. Tlak na prostor však nemusejí vytvářet jen rozměry průhledu (viewportu), ale také kvantita obsahu.

Podobně jako jsou koneční uživatelé vystaveni nutnosti operovat se zařízeními, která mají obrazovky o různých velikostech, jsou editoři obsahu vystaveni nutnosti přidávat nebo ubírat obsah. Pro tyto potřeby slouží systémy správy obsahu (content management systems, CMS). Tohle činí předběžné návrhy webových stránek (tzv. mockupy) Photoshopu dvojnásobně zastaralými: jsou to momentky (snapshots) jen jednoho viewportu s obsahem jen v jednom stavu.

V tomto článku nastíním pomocí speciálně formovaných selektorů, jak docílit, aby CSS bral na vědomí kvantitu. Tyto selektory budu konkrétně aplikovat na jeden klasický problém: jak změnit zobrazení položek v nějakém horizontálním navigačním menu, když je jich příliš mnoho na to, aby se vešly do počátečního módu layoutu. Předvedu tedy, jak se přepnout z layoutu display: table-cell do display: inline-block, když počet položek v menu bude “větší nebo roven šesti”.

Nebudu se přitom spoléhat na žádný JavaScript, ani na logiku nějaké šablony, a značkování seznamu menu také zůstane stejné, nebude se mu připisovat třída. Protože tento postup používá pouze CSS, dodržuje princip oddělení zodpovědností (separation of concerns), podle něhož mají jasně definované role obsah (HTML) a prezentace (CSS). Layout má na starost CSS, a pokud je to možné, pouze CSS.

initial layout

Přítomno šest nebo více položek.

Toto řešení je dostupné na CodePen a v průběhu článku se na ně budeme odkazovat.

Aby se mi lépe objasňoval tento způsob kvalifikace kvantity, budu v článku reprezentovat HTML elementy prostřednictvím grafik s hlavonožcem. Zelený hlavonožec se zaškrtnutím reprezentuje prvek vyhovující právě použitému selektoru, červený hlavonožec s malým x je nevybraný prvek a zašedlý hlavonožec označuje neexistující prvek.

neexistující prvek

Počítání

Kvantitu prvků v daném kontextu určíte tak, že prvky spočtete. CSS sice neposkytuje explicitní “počítací API”, můžeme však tento problém vyřešit vynalézavou kombinací selektorů.

Počítání do jedné

Selektor :only-child poskytuje prostředek, jak stylovat prvky, pokud se objevují izolovaně. Umožňuje v podstatě “stylovat všechny dceřiné elementy konkrétního elementu, pokud se jako celkový počet těchto přímých potomků vrátí 1”. Kromě svého stájového druha :only-of-type je to jediný jednoduchý selektor, o němž se dá říct, že je založený na kvantitě.

V následujícím příkladu přidám pomocí selektoru :only-of-type speciální styl jakýmkoli tlačítkům, která jsou mezi sourozeneckými elementy jedinými elementy jejich elementového typu. Těmto osamoceným tlačítkům přidělím větší font-size, protože singularita svědčí o důležitosti.

button {
font-size: 1.25em;
}

button:only-of-type {
font-size: 2em;
}

 

Tohle je kritická část. Pokud bych začal s jedním tlačítkem, vecpal do něho font o větší velikosti, a pak přidával další tlačítka před ně nebo za ně, každé tlačítko by pak převzalo menší velikost fontu. Styl všech prvků v dané množině závisí na kvantitativní hranici dva: pokud je prvků “méně než dva”, ctí se větší velikost fontu. Podívejte se znovu na kód, ale tentokrát berte v úvahu pojem “méně než dva”:

 

button {
font-size: 1.25em;
}

button:only-of-type {
font-size: 2em;
}

méně než dva

Pokud vám lépe vyhovuje logika s negací, převraťte logiku CSS v záhlaví tak, že podmínku změníte na „více než jeden“.

 

/* "Více než jeden" vede na menší velikost fontu */
button {
font-size: 2em;
}

button:not(:only-of-type) {
font-size: 1.25em;
}

více než jeden

 

Kvantita n

Stylování elementů na základě mezí “více než jeden” a “méně než dva” je sice bezvadný trik, skutečně flexibilní rozhraní “kvantitativního dotazu” by však mělo akceptovat jakékoli množství. To znamená, že bych měl být schopen stylovat “více nebo rovno n” pro jakoukoli hodnotu n. Pak budu také moci v našem navigačním menu stylovat podle podmínky “více nebo rovno šesti”.

S ohledem na tento konečný cíl nejprve promysleme, jak zařídit, abychom byli schopni stylovat konkrétní kvantity, jako jsou “celkem přesně šest” nebo “přesně 745”? Jak se s tím vypořádat? Potřebujeme nějaký selektor, který by umožňoval numericky projít množinu jakéhokoli počtu prvků (spočítat je).

Naštěstí existuje selektor :nth-last-child(n) přebírající číslo “n”, dovoluje počítat prvky množiny od jejího konce směrem k začátku. Například, selektoru :nth-last-child(6) vyhovuje mezi sourozeneckými elementy šestý element od konce.

Zajímavější to začne být, když zřetězíme :nth-last-child(6) s :first-child, čímž zavedeme druhou podmínku. V tomto případě hledáme jakýkoli prvek, který je šestým prvkem od konce a zároveň prvním prvkem.

 

li:nth-last-child(6):first-child {
/* stylování zelený hlavonožec */
}

Pokud takový prvek existuje, musí mít množina přesně šest prvků. Vlastně jsem napsal CSS, který říká, na kolik prvků se dívám.

html-elementy-first-child

 

Pak už zbývá jen pověřit tento klíčový prvek, aby takto nastyloval ostatní prvky množiny. K tomu použiju selektor, kterému se říká obecný sourozenecký kombinátor (general sibling combinator).

html-elementy-last-child

Pokud jste se ještě s tímto druhem selektoru nesetkali, úsek ~ li v li:nth-last-child(6):first-child ~ li znamená “jakékoli elementy li, které se vyskytují za li:nth-last-child(6):first-child”. V následujícím příkladu převezme každý z elementů zelenou barvu fontu jen tehdy, pokud jich je celkem přesně šest.

 

li:nth-last-child(6):first-child,
li:nth-last-child(6):first-child ~ li {
color: green;
}

 

Více nebo rovno šesti

Zaměřovat se na konkrétní kvantitu — ať už je to 6, 19 nebo 653 — není nijak zvlášť užitečné, protože se tím řeší jen specifické situace. Obdobně by bylo celkem k ničemu používat v mediálních dotazech @media konkrétní šířky místo min-width nebo max-width:

 

@media screen and (width: 500px) {
/* stylování pro viewporty široké přesně 500px */
}

 

navigačním menu chci skutečně přepnout layout při dosažení jisté meze: při kvantitativním předělu. Chci přepnout při šesti nebo více položkách — ne při přesně šesti položkách. Když se dospěje k této hranici, chci přejít od distribuovaného tabulkového layoutu k jednodušší zalamované konfiguraci inline-block. A co je důležité, chci zachovat tuto přepnutou konfiguraci, pokud se počet položek dále zvyšuje.

Otázkou je, jak vlastně začít sestrojovat takový selektor? Je to záležitost ofsetů.

Argument n+6

Jiný aritmetický argument, který může přebírat selektor :nth-child, má tvar “n + [celé číslo]”. Například, :nth-child(n+6) styluje všechny prvky v množině počínaje šestým prvkem.

do nekonečna

Přestože se určitě dá tento tvar v jistých situacích aplikovat tak, jak je, není svou podstatou selekční metodou “vnímající kvantitu”: nestylujeme proto, že je zde celkem šest nebo více prvků; stylujeme prostě prvky, kterým jsou při enumeraci (když je počítáme) přiřazená čísla větší než pět.

Abychom problém vyřešili řádně, potřebujeme něco jiného. Vytvořit množinu prvků, která vyloučí posledních pět prvků. Pomocí opaku :nth-child(n+6) — :nth-last-child(n+6) — mohu aplikovat vlastnosti přepnutého layoutu na všechny “poslední prvky” počínaje šestým, když se počítá (přiřazují čísla prvkům) od konce směrem k začátku množiny.

 

li:nth-last-child(n+6) {
/* zde jsou vlastnosti */
}

 

Tím vynecháváme posledních pět prvků množiny o jakémkoli počtu prvků, což znamená, že pokud zredukujete množinu tak, že bude mít méně než šest prvků, přestanete vidět vybrané prvky. Je to jistý druh efektu, kterému se říká „posuvné dveře“ (“sliding doors”).

sliding doors

Pokud má množina šest nebo více prvků, stačí už jen nastylovat i těch posledních pět prvků. To je snadné: když je víc než šest položek, musí existovat jedna nebo více položek, které pro podmínku nth-last-child(n+6) “vracejí true” (v žargonu JavaScriptu). Jakýkoli a všechny dosud existující prvky lze zkombinovat s “~”, aby stylování účinkovalo na všechny následující položky (včetně posledních pěti).

více-méně než 6

hranice

(breakpoint)

Překvapivě hutné řešení našeho problému je:

 

li:nth-last-child(n+6),
li:nth-last-child(n+6) ~ li {
/* zde jsou vlastnosti */
}

Číslo 6 lze pochopitelně nahradit jakýmkoli kladným celým číslem, třeba i 653279.

Méně nebo rovno n

Podobně jako v dřívějším příkladu na :only-of-type, i zde lze logiku převrátit, přepnout z “více nebo rovno n” na “méně nebo rovno n.” Kterou z logik použijete, závisí na tom, který ze stavů považujete za přirozenější výchozí stav. “Méně nebo rovno n” nastavíte tak, že uvedete záporné n a znovu zavedete podmínku :first-child.

 

li:nth-last-child(-n+6):first-child,
li:nth-last-child(-n+6):first-child ~ li {
/* zde jsou vlastnosti */
}

Použití znaménka “-” vlastně přepíná směr výběru: nyní neukazujeme od šesté položky prvku ke startu, ukazujeme od šesté ke konci. V obou případech selektor zahrnuje šestou položku.

nth-child versus nth-of-type

Všimněte si, že jsem v předchozích příkladech použil :nth-child() a :nth-last-child(), nikoli :nth-of-type() a :nth-last-of-type(). Protože zde pracuji s elementy <li> a protože elementy <li> jsou jediní legitimní přímí potomci elementů <ul>, fungovaly by zde oba, :last-child() i :last-of-type().

Rodiny selektorů :nth-child() a :nth-of-type() nabízejí různé výhody v závislosti na tom, čeho se pokoušíte dosáhnout. Protože je :nth-child() agnostický vzhledem k elementům, můžete popsanou techniku používat přes sourozence různých elementových typů:

<div class="container">
<p>...</p>
<p>...</p>
<blockquote>...</blockquote>
<figure>...</figure>
<p>...</p>
<p>...</p>
</div>
.container > :nth-last-child(n+3),
.container > :nth-last-child(n+3) ~ * {
/* zde jsou vlastnosti */
}

(Všimněte si, jak zde udržuji agnosticizmus elementů pomocí univerzálního selektoru. :last-child(n+3) ~ * znamená “jakýkoli element jakéhokoli typu, který následuje za :last-child(n+3)”.)

Naproti tomu předností :nth-last-of-type() je, že jste s ním schopni zaměřit se na skupiny jistých elementů, i když jsou přítomni další sourozenci odlišných typů. Můžete se například zacílit na kvantitu odstavců, jako v následujícím fragmentu, navzdory tomu, že jsou okolo nich breakpointy v podobě elementů <div> a <blockquote>.

 

<div class="container">
<div>...</div>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<blockquote>...</blockquote>
</div>
p:nth-last-of-type(n+6),
p:nth-last-of-type(n+6) ~ p {
/* zde jsou vlastnosti */
}

 

Podpora selektorů

Všechny selektory CSS2.1 a CSS3, které jsou použité v tomto článku, podporují Internet Explorer 9 a vyšší, včetně všech přiměřeně novějších prohlížečů mobilních a přenosných zařízení.

Podpora Internet Exploreru 8 je pro většinu selektorových typů dobrá, ale prakticky vzato jen částečná, proto budete možná raději uvažovat o nějakém polyfillu JavaScriptu. Alternativou pro “bezpečnější” layoutové strategie by mohlo také být párování selektorů se specifickými třídami IE9. Pokud jde o navigační menu, bezpečnější volba je ta, která bere v úvahu možnost většího množství položek, a to pomocí inline-block. Deklarační blok by mohl vypadat takhle:

 

nav li:nth-last-child(n+6),
nav li:nth-last-child(n+6) ~ li,

.lt-ie9 nav li {
display: inline-block;
/* atd. */
}

 

Ve skutečném světě

Předpokládejme, že naše navigační menu patří do nějakého webu spravovaného obsahem. V závislosti na tom, kdo administruje dané téma, bude zaplněno větším nebo menším počtem voleb. Někteří autoři se snaží udržet co největší jednoduchost, a proto poskytují jen odkazy typu “Domů” a “O nás“, zatímco jiní přecpávají svá menu spoustou voleb v podobě zakázkových stránek a kategorií.

Když poskytnete alternativní layouty v závislosti na počtu prezentovaných položek, budete moci elegantněji tolerovat všelijaké implementace daného tématu: vypořádáte se s variabilním obsahem a tím možná i s variabilními rozměry obrazovky.

initial layout

Máte to: můžete dát hlavonožcům sbohem! Nyní můžete do svého repertoáru jako stylovací podmínku přidat kvantitu.

Obsahově nezávislý design

Responzivní webový design řeší jeden důležitý problém: činí stejný obsah dobře stravitelný pro odlišná zařízení. Aby se lidem doručoval odlišný obsah jen proto, že mají různá zařízení, už není přijatelné. Obdobně je nepřijatelné, aby design diktoval povahu obsahu. Nemůžeme editorovi říct: “Tohle musíte vyhodit, jasné? Design by vypadal blbě.”

Jaký tvar však má obsah mít, a kolik ho bude v každém daném okamžiku, se často nedá přesně určit — jindy to nevíme vůbec. A nemůžeme se vždycky spolehnout na zalamování textu a uřezávající skripty. Abychom se dostali k opravdové obsahové nezávislosti, je třeba vyvíjet nové nástroje a techniky. Kvantitativní dotazy představují jen jeden nápad v tomto duchu.

Webový design charakterizuje proměnlivost, různorodost a neurčitost. Nevíme, co bude. Konkrétně, je to mód vizuálního designu, který nemá manifestovat nějakou formu, ale předvídat různorodé formy, jakých možná může něco někdy nabýt. Někoho může takový zákazník nesnesitelně konsternovat, pro vás a pro mne je však výzvou, ze které se radujeme. Podobně jako téměř nepolapitelný obří kalmar, i on je vážně mazaný všemi mastmi.

O autorovi

Heydon Pickering

Heydon Pickering je designér a vývojář rozhraní působící ve městě Norwich ve Velké Británii. Je vůdčím designérem u Neontribe a editorem přístupnosti (accessibility) pro Smashing Magazine, kde je také dostupná jeho kniha Aplikace pro všechny (Apps For All).

O překladu:

Článek byl převzat a přeložen pro interval.cz se svolením serveru alistapart.com.

Přeložil: RNDr. Jan Pokorný
Znění původního článku najdete na Quantity Queries For CSS

 

Štítky: CSS

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

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