Na konferenci CSS Day konané v červnu 2014 jsem uvedl, s mírným rozechvěním, bizarní tříznakový CSS selektor. Pojmenoval jsem ho “lobotomizovaná sova”, protože trochu připomíná bezvýrazný upřený soví pohled, a ukázalo se, že to byla nejoblíbenější část mé přednášky. Viz níže.

Nemohu říci, zda posluchači zatleskali způsobu myšlení, jaké dalo vzniknout této invenci, nebo se naopak nervózně mírně pousmáli mé smělosti zařadit tak podivný a zdánlivě neupotřebitelný koncept. Možná že jsem ale nevědomky hovořil do sálu plného nadšených ochránců sov a podporovatelů sovího útulku. Prostě nevím.

 

 

Celá přednáška z CSS day v originálním znění

Zmíněný selektor lobotomizovaná sova vypadá takto:

* + *

Navzdory tomu, že název není dostatečně úctyhodný a forma na pováženou, pro mne už selektor lobotomizovaná sova není pouhá myšlenková konstrukce. Je výsledkem neutuchajících experimentů konaných za účelem automatizace layoutu plovoucího obsahu. Soví selektor je “axiomatický” selektor s nenasytnou kompetencí. A protože je takový, budou se mnozí zdráhat ho použít, a leckoho dokonce poděsí, že ho zařazuji do ostrého kódu.

Hodlám však předvést, jak může tento selektor zredukovat přecpanost kódu nadbytečnými či nepoužívanými prvky, urychlovat vývoj a pomáhat při automatizaci stylování libovolného, dynamického obsahu.

Stylování podle předpisu

Profesionální designéři webového rozhraní si téměř všeobecně zvykli stylovat HTML elementy normativně, neboli předpisově. Vymyslíme nějaký objekt rozhraní a vytvoříme pro něj styly, které jsou do značkování ručně vepsané jako “háky”.

To, k čemu dospějeme nejčastěji, je selektor třídy, bez ohledu na to, že přísluší jen do prezentace, ne do sémantické interoperability. Přestože jsou prvky a většina atributů předurčené a standardizované, třídy jsou zástupci obdarovávající nás svobodou autorství. Jsou to právě třídy, která nám dávají kontrolu nad věcmi.

.my-module {

/* … */

}

CSS frameworky jsou v podstatě knihovny nestandardních, na třídách založených šifer, se záměrem formovat explicitní vztahy mezi styly a jejich elementy. Jsou chváleny za svou způsobilost pomáhat designérům produkovat rychle atraktivní rozhraní a kritizované za nevyhnutelné nedostatky týkající se přístupnosti (accessibility), které vyplývají z toho, že se začíná od stylu (forma), nikoli od obsahu (funkce).

< !– Sémanticky nesprávné „tlačítko“, nemůže získat fokus –>

<a class=“ui-button“>Stiskni mě</a>

Ať už budete používat nějaký framework, nebo svou vlastní metodologii, mód stylování podle předpisu také zakazuje neodborné obsahové editory. Vyžaduje totiž nejen vědomosti o prezentačním značkování, ale také přístup k takovému značkování, aby se styly zakódovaly tak, jak je předepsáno. WYSIWYG editory a nástroje, jako je Markdown, nevyhnutelně postrádají takovouto složitost, takže takové stylování nepřekáží redakčnímu procesu.

Přecpanost

Bez ohledu na to, zda můžete vytvářet a udržovat prezentační značkování, přetrvává otázka, zda byste měli takto značkovat. Když přidáváte prezentační šifry do dříve hutného značkování, nevyhnutelně ho zahltíte. A co za to? Umožní to zredukovat přecpanost stylového předpisu?

Když zvolíme stylování výhradně pomocí pojmenovaných elementů, děláme tu chybu, že tvrdíme, že HTML elementy žijí v jakémsi vakuu, že nejsou ani předmětem dědění, ani že nejsou obecně stejné. Když s elementem zacházíme jako že “tuhle věc je třeba stylovat”, jsme náchylní redundantně ručně nastavovat pro element některé takové hodnoty, které už měly být v kaskádě definované někde výše. Když přidáváme do projektu nové moduly, vlastně tím přecpanosti otevíráme dveře dokořán, a pak je těžké udržet ji na uzdě.

.module-new {

/* Takže… co je tu skutečně nového? */

}

Preprocesory přidávají různé proměnné, metodologie CSS založené na objektech zase zhusta aplikují opětovně využitelné třídy “objektů” a my se snažíme pytli písku zamezit této povodni přecpanosti. Je to přímo obsese našeho odvětví. Několik opatření se už skutečně vyhýbá normativní (předepisující) filosofii, protože ta především vyvolává otylost stylových předpisů. Některé interpretace objektově orientovaných CSS dokonce trvají na zploštělé hierarchii stylů, citují specifičnost jako problém, který je třeba překonat. V podstatě tím redukují CSS na SS a popírají jejich klíčové schopnosti.

Nepíšu to proto, abych tyto přístupy naprosto zatracoval, existují ale i jiné metody, které prostě mohou být za jistých podmínek efektivnější. Držte si klobouky, jedeme z kopce.

Výkon selektoru

S potěšením připouštím, že jakmile čtenáři uviděli na začátku článku v * + * ty dvě hvězdičky, začali někteří z nich prudce vrtět hlavou, aby energicky vyjádřili jasný nesouhlas s něčím takovým. Pro tento případ ale existuje precedens. Univerzální selektor je vskutku mocný nástroj. Jako takový může také vykonávat mnoho dobrých skutků, ne jen páchat zlo. Než se však k tomu dostaneme, chci se vypořádat s vnímaným problémem výkonu selektorů.

Všechny studie, které jsem četl, včetně těch, které napsali Steve Souders a Ben Frain, došly k závěru, že rozdíly ve výkonu různých typů selektorů CSS lze zanedbat, že jsou nevýznamné. Vskutku, Frain usoudil, že “nemá cenu se lopotit se selektory používanými v moderních prohlížečích, nestojí to za to”. Ještě jsem nečetl žádný protipříklad, přesvědčivý důkaz, který by byl v rozporu s těmito zjištěními.

Podle Fraina může potíže způsobovat něco jiného, velké množství CSS selektorů — přecpanost; konkrétně zmiňuje nepoužívané deklarace. Jinak řečeno, nemá valný smysl určovat, jakou mají selektory tříd “rychlost”, když skutečné potíže s výkonem způsobuje jejich nadměrné rozmnožování. Totéž působí gigantické soubory JPEG, nebo když se používají kompletní sady webových fontů, ne jejich podmnožiny.

Naproti tomu simultánní kontrola selektoru * nad mnoha elementy přispívá ke stručnosti, pomáhá zredukovat velikost souboru a vylepšit výkon.

Skutečné trable spojené s univerzálním selektorem spočívají v tom, že sám o sobě nereprezentuje žádný velmi podmanivý axiom — nevyjadřuje nic inteligentnějšího, než “styluj, ať je to cokoliv”. Vtip je v tom, spoutat tento základní selektor, zapřáhnout ho, a pak s ním formovat složitější výrazy, které berou v úvahu patřičný kontext.

Přidělování okrajů

Potíže spojené s omezováním stylů na objekty tkvějí v tom, že ne všechno se dá samo o sobě považovat za nějakou vlastnost nějakého objektu. Vezměme třeba okraje: okraje jsou něco, co se nachází mezi elementy. Udělovat jen tak, pro nic za nic, nějakému elementu horní okraj (top margin) nemá smysl, bez ohledu na to, kolikrát (zřídka, skoro pořád) to děláte. Je to něco podobného jako natřít lepidlem jednu stranu nějakého objektu dřív, než vůbec určíte, zda ho budete vůbec chtít k něčemu přilepit a co by to něco vlastně mohlo být.

.module-new {

margin-bottom: 3em; /* cože, vždycky? */

}

Co potřebujeme? Nějaký výraz (selektor), jemuž budou vyhovovat elementy jen tehdy, pokud potřebují nějaký okraj. Tedy, jen elementy, které jsou v nějakém kontextovém vztahu (u nichž to ze souvislostí vyplývá) s jinými sourozeneckými elementy. Právě tohle dělá operátor sousedního sourozence: má tvar x + n, můžeme přidat horní okraj jakémukoli n, pokud x přišel bezprostředně před ním.

Ve standardním stylování podle předpisu bychom velmi rychle dospěli k mnohomluvnému zápisu, protože bychom uvnitř rozhraní vytvářeli pravidla pro každé z různých možných párování elementů. My se zde proto rozhodneme pro výše zmíněný univerzální selektor a vytvoříme svou soví tvář. Axiom zní: “všechny elementy v toku dokumentu, které bezprostředně následují za jinými elementy, musejí obdržet horní okraj jeden řádek.”

* + * {

margin-top: 1.5em;

}

Úplnost

Za předpokladu, že velikost fontu (font-size) pro odstavce je 1 em a jeho výška řádku (line-height) 1,5, právě jste nastavili výchozí okraj jednoho řádku mezi všemi po sobě jdoucími elementy toku všech variet a v jakémkoli pořadí. Ani my, vývojáři, ani lidi sestavující pro projekt obsah, nikdo se nemusí strachovat, že se na nějaký element zapomnělo, a že hrozí, že nebude mít standardní okraj, až se bude realizovat za nějakým jiným elementem. Kdybychom chtěli téhož docílit normativním stylováním podle předpisu, museli bychom předjímat specifické elementy a udělovat jim jednotlivě hodnoty pro okraj. Otravné, užvaněné a náchylné k tomu, že to stejně nebude kompletní.

Místo abychom psali styly, vytvořili jsme stylový axiom: překlenovací princip pro layout toku obsahu. Je také značně dobře udržovatelný; pokud chcete změnit výšku řádku (line-height), stačí změnit tuto jedinou hodnotu margin-top a jste hotovi.

Povědomí kontextu

Je to ještě lepší, než se zdá. Tím, že jsme aplikovali okraj jen mezi elementy, negenerujeme žádné redundantní okraje (další vrstvy lepidla) předurčené k tomu, aby se zkombinovaly s vnitřním okrajem neboli výplní (padding) rodičovských elementů. Porovnejte řešení (a), v němž se všem prvkům přidává horní okraj, s řešením (b), které používá soví selektor.

podvedomi_kontextu

V levém sloupci diagramu je horní okraj vyznačen tmavě šedou barvou, výplň světle šedou.

Nyní rozeberme, jaké bude chování, když vezmeme v úvahu vnořování. Jak jste viděli výše, když jsme použili soví selektor a jen hodnotu pro horní okraj, ani první, ani poslední element množiny elementů nebudou nikdy prezentovat redundantní okraj. Kdykoli vytvoříte nějakou podmnožinu těchto elementů tím, že ji zabalíte do vnořeného rodiče, budou se na podmnožinu aplikovat tatáž pravidla, jaká se aplikovala na nadmnožinu. Žádný okraj, bez ohledu na úroveň vnoření, nebude mít výplň. Při tomto druhu algoritmické elegance se chráníme před tím, aby bylo naše rozhraní ohrazované zbytečným prázdným prostorem.

podvedomi_kontextu_2

Je to neobyčejnou měrou méně mnohomluvné a robustnější, než když se k danému problému nepřistupuje axiomaticky a dodatečně (ex post) se odstraňují zbytky lepidla, jak zdráhavě navrhl Chris Coyier v “Jak stanovit prázdné místo na dolním konci modulů”. Právě tento článek, což musím zdůraznit, mi pomohl přijít na nápad s lobotomizovanou sovou.

.module > *:last-child,

.module > *:last-child > *:last-child,

.module > *:last-child > *:last-child > *:last-child {

margin: 0;

}

Poznamenejme, že to funguje jen tehdy, máte-li definovaný nějaký kontext “module” (vpravdě otázka na tělo editora obsahu), a vyžaduje mít správný odhad počtu možných úrovní vnoření. Zde se podporují nejvýše tři.

Design řízený výjimkami

Doposud jsme ještě nepojmenovali ani jeden jediný element. Prostě jsme napsali nějaké pravidlo. Teď hodláme těžit z přednosti, kterou se pyšní soví selektor, má totiž nízkou specifičnost. Začneme uvážlivě sestavovat výjimky, a budeme využívat přitom výhod, které poskytuje kaskáda, ne ji zavrhovat, jak činí jiné metody.

Odstavce zarovnávané do bloku odsazované jako v knihách

p {

text-align: justify;

}

p + p {

margin-top: 0;

text-indent: 2em;

}

Poznamenejme, že odsazené jsou jen odstavce jdoucí těsně za sebou, což je tradiční — další vítězství pro operátor sousedního sourozence.

Kompaktní moduly

.compact * + * {

margin-top: 0.75em;

}

Pokud to považujete za účelné, využívejte trochu i objektovou orientaci založenou na třídách. Například lze vytvořit opětovně využitelný styl pro kompaktnější moduly. V tomto příkladu všechny elementy, které potřebují okraj, ho dostanou jen ve velikosti půl řádku.

Widgety s pozicováním

.margins-off > * {

margin-top: 0;

}

Soví selektor je expresivní selektor, takže bude ovlivňovat i různé widgety, jako jsou mapy, v nichž se všechno pozicuje přesně. Tohle je prostý vypínač. Widgety tohoto druhu se ale budou stále více vyskytovat v podobě webových komponent, kde se náš algoritmus nastavování okraje stejně dědit nebude. Je to tak díky schopnosti zvané zapouzdření stylů v Shadow DOM.

Krása jednotek em

Přestože několik výjimek bude nevyhnutelných, když zapřáhnete do svých služeb jednotku em, konkrétně pro hodnotu okraje, budou se okraje upravovat automaticky vzhledem k jiné vlastnosti, velikosti písma, font-size. Kdykoli někde upravíme font-size, okraj (margin) se tomu přizpůsobí: rozestup jeden řádek bude pořád rozestup jeden řádek. To se hodí zejména tehdy, když zvětšujete nebo zmenšujete velikost písma (font-size) elementu body přes nějaký dotaz @media.

Pokud jde o záhlaví, stojí při nás štěstěna ještě víc. Máte-li ve stylovém předpisu sadu velikostí písma v jednotkách em, nastaví se pro každé záhlaví patřičný okraj (uvozující prázdné místo), aniž byste museli napsat jediný řádek dodatečného kódu.

heading

 

Frázované prvky

U této deklarace stylu bude naším záměrem, aby se dědila. Takto ostatně bylo původně navrženo, aby pracovaly styly i CSS všeobecně. Já si ovšem uvědomuji, že jsou lidé, které může poněkud znepokojovat, jak nenasytný tento selektor je, zejména poté, co si zvykli vyhýbat se dědění jako čert kříži.

Už jsem probral několik výjimek, které si možná budete přát zaměstnat ve svůj prospěch, ale pokud by to mělo ještě víc pomoci, uvědomte si, že frázované prvky s typickou hodnotou display inline budou dědit horní okraj, ale nebudou ovlivněny z hlediska layoutu. Inline elementy respektují pouze vodorovný okraj, což je specifikované a standardní chování přes všechny prohlížeče.

inline

Pokud jste zjistili, že soví selektor často překrýváte, možná to má nějaké hlubší systémové příčiny v designu. Soví selektor se zabývá plovucím obsahem (flow content) a tento druh obsahu by u vás měl převažovat. U většiny rozhraní nemohu doporučit značnou závislost na pozicovaném obsahu, protože se tím narušují implicitní tokové vztahy. Dokonce i mřížkové systémy se svými plovoucími sloupci by neměly požadovat víc, než nějaký jednoduchý selektor .row > *, který je resetuje aplikováním margin-top: 0.

row

Závěr

Přestože jsem velmi slabý v matematice, mám velkou slabost pro Euklidovy postuláty: sadu dále neredukovatelných pravidel neboli axiomů, které formují základy složitých a obdivuhodných geometrií. Díky Euklidovi chápu, že i ty nejsložitější systémy se musejí opírat o nějaká fundamentální pravidla, a CSS nejsou žádnou výjimkou. Přestože je u složitého rozhraní nutným krokem k jeho vyspělosti modularizace, rozhraní, které důsledně nedodržuje nějaké základní hlavní principy, bude postrádat preciznost a srozumitelnost.

Soví selektor umožňuje nejen mít kontrolu nad plovoucím obsahem, je to také způsob, jakým je možné se této kontroly vzdávat. Když stylujete elementy podle kontextu a okolností, akceptujete tím, že struktura obsahu je — a měla by být — proměnlivá. Místo toho, abychom normativně předepisovali vzhled jednotlivých položek, budujeme systémy tak, aby mohly vzhled předjímat. Nepředepisujeme vzhled rozhraní vcelku, necháme na obsahu, ať vzhled určí sám. Předáváme řízení zpět lidem, kteří ho budou umět udělat.

Pokud na nějaké webové stránce úplně vypnete CSS, měli byste zpozorovat dvě věci. Zaprvé, stránka bude jistě flexibilní: obsah dobře padne viewportu bez ohledu na jeho rozměry. Zadruhé — za předpokladu, že jste napsali standardní, přístupné značkování — měli byste uvidět, že obsah je už stylovaný tak, že i když nebude vysoce atraktivní, dá se po něm slušně traversovat. Také o to se postaraly styly uživatelského agenta prohlížeče.

Naše úsilí rekultivovat a rozšiřovat vrozenou nezávislost zařízení nabízenou uživatelskými agenty stále pokračuje. Je na čase, abychom také pracovali na opětovném zavedení nezávislosti obsahu.

 

O autorovi

Heydon Pickering

Heydon Pickering je designér a vývojář rozhraní z Norwiche ve Velké Británii. Je vůdčím designérem u Neontribe a je accessibility editor pro Smashing Magazine, kde je k dostání také jeho kniha Apps For All.

Original article: Axiomatic CSS and Lobotomized owls

  • Translation: RNDr. Jan Pokorný
  • Language and expert collaboration: Marek Machač

Language of translation: Czech (for readers from Czech and Slovak republics). Translated with the permission of Alistapart.com. Other translations.

2 Příspěvků v diskuzi

  1. Díky za překlad, jsou tu pěkné a nové myšlenky.

    Také odstavec o výkonu selektorů je pro mne velice překvapivý, mnoho (ale ne nezbytně vyloženě na úrovni) zdrojů uvádí opak, bez nějakých větších podkladů.

    Tím více je lákavé použít http://amcss.github.io, což zase jiný a zajímavý přístup k CSS (ovšem tentokrát třídy dostanou slovo).

Odpovědět