Přejít k navigační liště

Zdroják » Webdesign » Kaskáda a další „problémy“ CSS: Jak je řešit, když vás pálí?

Kaskáda a další „problémy“ CSS: Jak je řešit, když vás pálí?

Články Webdesign

CSS své trable bezpochyby má. Pokud se ale jedná o organizaci a architekturu projektu, těžko o nich mluvit jako o problémech. Stejně jako jiné jazyky prostě nijak nespecifikuje, jak se máme starat o větší projekty. Musíme vzít na pomoc metodiky organizace kódu.

Nálepky:

Text vyšel původně na autorově webu.

Dneska se podíváme na tři problémy, které kritici stylům pravidelně otloukají o kaskádovou hlavu:

Než se dostaneme k architektuře – první věc, u které se musím pozastavit, je povaha jazyka. Tady jsem svého času dost často slýchával výtky ze strany programátorů.

Divný jazyk – ale dobře známý

CSS je kód. Není to však programovací, ale deklarativní jazyk, protože popisuje design. S tím se holt musíme smířit.

Řadě vývojářů se nelíbí z toho vycházející repetitivní povaha CSS, a tak si všelijak uzpůsobují a „zefektivňují“ zápis:

.nav {
  @extend %m-b-0;
  @extend %clearfix;
  @include pos-r;
  @include dis-b;
}

A je to. Z divného jazyka tím vytvoří ještě divnější. Nový jazyk, kterému rozumí autor a pár zasvěcených. Nikdo jiný.

CSS preprocesory přinesly mnoho dobrého, ale také možnost vytvořit si zcela nové jazyky, velmi málo podobné kaskádovým stylům. A to je peklo.

CSS je třetí nejčastěji používaný jazyk, takže mu prostě většina vývojářů a vývojářek rozumí. Když nad ním vytvoříme jazyk nový, zkomplikujeme tím zapojování nových lidí do vašeho projektu. Pro ty, kteří spravují více projektů, jsou silně proprietární nádstavby nad styly komplikující.

Pořadí vlastností a specifičnost – bez metodik to nejde

Dvě ze tří vlastností kaskády způsobily dva ze tří šedivých vlasů na hlavách těch zasloužilejších z nás. Pořadí vlastností a specifičnost, neboli váha selektorů.

Ano, uznávám – to, že poslední pravidlo vyhrává, ale zároveň ještě záleží na váze selektoru, je trochu složitější. Ale takhle jsou kaskádové styly postavené. Se s tím smiř.

Vezměme toto HTML:

<section class="box">
  <div class="tabs">
    <h2 class="mb-0">…</h2>
  </div>   
</section>

CSS kód si často naběhne sám:

/* base.scss */

h2 {
  color: red;
}

/* helpers.scss */

.mb-0 {
   margin-bottom: 0;
}

/* components/box.scss */

.box h2 {
  color: green;
  margin-bottom: 1rem;
}

/* components/tabs.scss */

.tabs h2  { 
  background: blue; 
  margin-bottom: 1rem;
}

Máte? Tak a teď vezměme, že cílem bylo, aby nadpis <h2> byl v boxíku zelený a neměl spodní vnější okraj (margin). Jenže:

  • díky pořadí v kódu vyhraje selektor .tabs h2 a ten nastaví modrou barvu
  • díky specificitě nezafunguje helper .mb-0 a <h2> bude mít spodní vnější okraj o velikosti 1rem

Kaskáda nám to pokazila. Tady pardon – ne kaskáda, ale špatně napsaný kód, který kaskádu nerespektoval.

Nezbývá než se s kaskádou smířit a přizpůsobit tomu dvě věci:

  • Držet specifičnost co nejníže
    To je ostatně jedno z pravidel metodiky OOCSS, ze kterého pak vychází BEM. V tomto příkladě jsou samozřejmě špatně selektory .box h2 a .tabs h2.
  • Nastavit pořadí kategorií stylů podle rostoucí specifičnosti
    To hlásá například metodika ITCSS. V tomto příkladu by se hodilo změnit pořadí v kódu tak, aby užitková třída (.mb-0) následovala až za komponentami.

Lépe napsaný kód vypadá takto:

<section class="box">
  <div class="tabs">
    <h2 class="head head--green mb-0">…</h2>
  </div>   
</section>

CSS:

/* base.scss */

h2 {
  color: red;
}

/* components/head.scss */

.head { … }

.head--green {
  color: green;
}

/* helpers.scss */

.mb-0 {
   margin-bottom: 0;
}

Občas je také výhodnější utilitám zvýšit specificitu nebo použít !important. Hlavně v situacích, kdy je přidáváme do starého a nezbedného kódu s nevyzpytatelnou úrovní specificity.

Je dobré používat komponentový přístup a zbavit elementy závislosti na kontejneru. Prostě používat OOCSS, abychom se vyhnuli problémům s kaskádou.

Tady se dotýkáme i toho, že aby to celé dávalo smysl, i design musí být komponentový.

Globální platnost – komponentový přístup a metodiky to řeší

To, že každý selektor platí globálně, byl svého času první argument pro používání CSS v JS. Vlastně jsem mu ale nikdy úplně plně nerozumněl, hlavně omílanému srovnání s globálními konstantami v programovacích jazycích.

Na kódu výše je vidět, jak bojujeme se stylováním <h2>. Jenže při použití OOCSS nebo ještě lépe BEM problémy s globálností neplatí. Všechny komponenty, jejich podelementy nebo modifikátory mají prefix a název komponenty:

.box h2 → .head--green

Zůstává jen jediný problém – s vymýšlením unikátních prefixů a pojmenováním komponent.

Není to dokonalé řešení, ale leta to funguje velké části kodérů včetně mě. Mimochodem, zbývající problémy s globální platností snad jednou vyřeší nějaká standardizovaná technologie typu ShadowDOM.

Externí závislosti – do trezoru s nimi

I kodéři a kodérky, kteří udržují kód v čistotě, jsou při nasazení externí knihovny do projektu v úzkých.

Cizí knihovny jsou z pohledu CSS obvykle napsány přímo strašidelně. Možnost nastavit je přes proměnné preprocesorů je vzácná. Často používají selektory se zbytečně vysokou specifičností. A některé se vůbec nebojí vám přepsat váš vlastní kód. Odtud vede cesta už jen do ordinace doktora Chocholouška.

Pokud se komponenta dopouští agrese na vašem vlastním kódu, je to zlé. Do doby než budeme moci takové komponenty uzavřít do nějakého ShadowDOM, prostě nezbývá než dobře testovat, než nějakou vybereme.

Vezměme tento ošklivý příklad:

/* base.scss: */

h2 { … }

/* libraries/lightbox.scss (padouch) */

#lightbox #heading h2 { … }

/* components/heading.scss (můj krásný kód je v čudu) */

.heading { … } 

Bez technologií typu CSS v JS nebo ShadowDOM izolace padoucha nedosáhneme. Máme tu ale i problémy ze „zašpiněním“ čístého kódu. To je řešitelné – externí závislosti a boj s nimi se prostě dají do externí složky:

/* base.scss: */

h2 { … }

/* components/heading.scss (můj krásný kód je v čudu) */

.heading { … } 

/* libraries/lightbox.scss (padouch) */

#lightbox #heading h2 { … }

/* libraries/lightbox-custom.scss (boj s padouchem) */

#lightbox #heading h2 { … }

Na složku libraries/ pak samozřejmě nepouštíme Stylelint a vůbec se k ní raději moc nepřibližujeme.

Tak dobře. Ještě zbývá pár chytrých rad v závěrečném shrnutí:

  • Ať už vám CSS připadá divné nebo ne, nezhoršujte kód vymýšlením vlastního jazyka v preprocesorech.
  • Respektujte kaskádu: držte specificitu co nejníže, řaďte podle ní soubory v projektu a snažte se o komponentový přístup.
  • Docela účinný lék na globální platnost selektorů je opět komponentový přístup a metodika BEM.
  • Externí závislosti izolujte alespoň kvůli lintování do zvláštní složky.

ebook-vdcss3-prebal-final

Kniha „Vzhůru do (responzivního) designu“

Kompletní průvodce návrhem a implementací responzivních uživatelských rozhraní v e-booku a knize. Více informací.

Komentáře

Subscribe
Upozornit na
guest
18 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Jakub Stratil

Díky za článek, je dobře a vystižně napsanej.

Snažit se po někom předělat stylování s hlubokým, nespecifickým zanořením zahrnující tagy, je opravdu peklo. :)

Mlocik97

Ale je mi ťažšie sa naučiť CSS než nejaký iný jazyk, trebárs aj programovací.

Dor

Mám to stejné. Po téměř deseti letech práce s HTML+CSS nejsem schopen dosáhnout výsledků, kterých jsem dosahoval po půl roce práce s WPF. CSS je asi moje nejméně oblíbená technologie, kterou musím používat. A to navzdory tomu, že musím používat i taková pekla, jako je PHP.

Mlocik97

Specialista? No ja bych ho pre svoj projekt fakt potreboval. Inak svoj projekt nedokončím ani do vianoc roku 2030.

Dor

S WPF mohu designovat GUI sám. S HTML + CSS potřebuji specialistu, který když je dobrý, tak dokáže v CSS skoro to, co běžný programátor v XAML. Takže to nejspíše vymysleli zednáři, aby bylo dost profesí a bylo jak rozdělovat peníze mezi lidi. Už to začíná dávat smysl.

Článek se mi líbí a je napsán skvěle, ale už to, že je takový článek potřeba, říká o CSS něco nepěkného. HTML+CSS má ještě spoustu rezerv a bude muset být ještě hodně upravováno a ohýbáno ze svých původních ideí, než se při tvorbě GUI vyrovná XAMLu. To, že je to jeden z nejpoužívanějších jazyků, je jen proto, že v prohlížeči není na výběr.

martin

Připadá mi, že tvůrci specifikace HTML+CSS myslí jen na zpravodajské portály a blogy a opomíjejí business aplikace, které používají HTML jako frontend, včetně např. eshopů. Myslím, že třeba element by se využíval mnohem víc, než nějaký .

Samotná existence metodik, které se marně snaží nad CSS vytvořit nějaký systém dokazuje, že CSS je navrženo nešťastně a nesystémově. Mě se nejvíc osvědčilo začít používat react.js s knihovnou emotion, která vrací do tvorby webů komponentový přístup.

Mlocik97

HTML je celkom OK, samozrejme je tam pár vecí ktoré tam chýbajú, ale nieje problém si čokoľvek do HTML pridať, ostatne síce na to je potrebnej JS ale to samo o sobe webaplikace potrebuje, takže v tom nevidím problém, trebárs ja si HTML korením Angularom. CSS to je pre mňa nočná mora. Najhoršie je že stále mám pocit že v každom prehliadači to funguje inak. Veľa vecí sa chová podivne a dosť nevyspytatelne.

Dor

XML je celkem OK. Samotné HTML je OK s výhradami. Je to takové špinavější XML. Ale dnes už se nepočítá s tím, že by ho někdo styloval bez CSS.

Mě vadí hlavně to, že je to pořád hodně orientované na stavění dokumentů, ale přitom v tom nezanedbatelné množství lidí tvoří GUI. Co se týče adresování elementů css selectorama, tak s tím bych se ještě srovnal, ale vadí mi jiné věci. Např. udělat blok (div), jehož výška je určena obsahem. Do toho bloku dát vlevo nějaký text a vpravo jiný blok, jehož výška bude určena rodičovským blokem. A do toho pravého bloku strčit blok, který bude zarovnaný vertikálně na střed. Ve WinForms nebo WPF žádný problém. V HTML + CSS jsou na to asi 3 postupy a žádný není úplně správně.

Mlocik97

Grid aj flexbox som koukal, ale i tak tomu nerozumím, a nevím jak spraviť layout ktorý by nebol v presnej mriežke.

+-------------------+-------------------+----------------+
|                   |                   |                |
|                   |                   |                |
|                   +-------------------+                |
|                   |                                    |
+-------------------+------------------------------------+

trebárs ako spraviť niečo takéto?

(p.s. moje ASCII arting je katastrofálne takže pššt, ak chcete recenzovať moju krezbu).

Dominik

Velmi dobre napisany clanok, hoc cakal som trosku viac prikladov, ale to nevadi. Ja pouzivam CSS uz vela vela rokov a 90% problemov mi vyriesilo prefixovanie, resp. kedze pouzivam preprocesor, tak pisanie zvlast scss suboru pre komponent a pouzivanie stromovej struktury (co sa transpiluje na prefixovane CSS). Len velmi malo kedy uz musim riesit nejaky problem so specifickostou selektoru alebo jeho vahou, maximalne su niektore veci zbytocne duplicitne (font-size a pod.) rozne po komponentoch, ale to je vlastne dobre, pretoze je to samostatny komponent a nech teda funguje aj bez okolitych ci rozne magicky zdedenych stylov, no nie?

Co sa tyka externych kniznic a frameworkov, toto bude stale boj a uznavam, ze tu neexistuje ziadna vseobecne fungujuca magia ako to dostat pod kontrolu. Ja si vzdy CSS framework vyberam este skor, ako zacnem robit aplikaciu a zistujem, ci mi bude vyhovovat a ci ho budem vediet modifikovat na svoje potreby (napr. boostrap celkom dobre ide). Ak mam framework, ktory sa modifikovat naozaj neda, alebo je to velmi pracne a nestabilne, tak ho bud nepouzijem, alebo zmenim svoj pristup a pouzivam len to, co mi ten framework/kniznica dovoli a snazim sa to obajit aj pred zakaznikom (to je niekedy velmi tazke, ale da sa aj to). Proste je to vec kompromisu.

No a co sa tyka kompatibility medzi browsrami, ano rozdiely tam su, ale rozhodne nesuhlasim s tym, ze jeden a ten isty CSS kod sa zobrazuje uplne inac na roznych browseroch. To platilo mozno 10 rokov dozadu, teraz uz urcite nie. Ak je takyto problem, vo vacsine pripadov ide o kombinaciu zleho (rozumej nevalidneho) HTML kodu a nasledne nestastne zvolenych CSS selektorov a nie to, ze browsre su ine. V momente ked pisem validne HTML, spravne uzatvaram tagy a davam si pozor na logicke plynutie stranky a neznasilnujem DOM miliardov nepotrebnych divov a spanov, mam minimum problemov. Tych par (kozmetickych) rozdielov sa uz potom da opravit celkom rychlo.

Mlocik97

ja riešil presne to isté, reálna veľkosť rodičovského elementu podľa veľkosti obsahu je jedno z nejhorších vecí ktorú by nekto mohol riešiť, ja to už neriešim vôbec, graficky ak sa to zobrazí správne, už mi je jedno jaké veľkosti reálne majú elementy ako div. Inak celý svoj projekt som skládal iba skrz positioning, floating a calc(); vyzerá to kazastrofálne ale jaksi cca funguje. Problém mám ale na iných miestach. Napríklad čo vôbec netuším je ako spraviť aby na mobile som mal hamburger menu a na počítači som mal to rozseklé v dvoch nav, medzi ktorými niečo ešte je. Mám to trocha zložitejšie, lebo jde o to že mám v „rohu“ hlavičku, vedla nej jeden navbar, pod ňou druhý nav bar, a pod prvým resp. napravo druhého mám obsah. Ďalší problém je päta, dajme tomu že obsah mám medzi 2 inými elemntami, stĺpcami, a pod obsahom na konci pätu, bočné elementy sú fixlé, obsah aj s pätou sa skroluje, a na mobile by mal trebárs pätu pod stĺpcom ktorý by bol pod obsahom. Tzv. jak cez styly vymeniť poradie tak aby zároveň päta opustila nadriadený element. To troška taky problematické. A jeden problém ktorý ma sere je tzv. „2px bug“, trebárs ak máš takýto kód:

<body>
    <div id="a">neco</div>
    <div id="b"><span>neco<span></div>
</body>

a css

body {margin: 0; padding: 0; line-height: 1.5;}
#a {height: calc(100%-20px); width: 100%;}
#b {height: calc(20px); width: 100%;}
span {font-size: 12px};

tak proč v chrome to funguje správne (bez scrollbaru) ale vo firefoxu mám scrollbar, a stránka je scrollovatelná o 2px? však 12px je menej ako 20px, text by nemal presahovať element #b ale vo FF presahuje, v chrome nie.

Mlocik97

inak možno mám v tam chybu v CSS (čo sa valídnosti týka), psal som to ručne, takže to neriešim, ide iba o princíp, u seba to mám správne, pozerám práve že asi u calc() som nedal medzeru medzi mínusom a hodnotou.

martin

Jen takový tip: zkoušel jsi flex? Od té doby, co jsem začal stylovat flexem, tak jsem float nepotřeboval a calc možná jednou. Fakt doporučuju.

Mlocik97

skoušel sem Grid aj Flex, pokaždé sa môj layout totálne rozbil.

Mlocik97

proste to neumím, CSS je moje najslabšia stránka čo sa týka webových technológií.

Mlocik97

Chcel by som vedieť jak ukotviť menu ak pre layout použijem CSS grid. Kedže podľa špecifikácie ak elementu v Gridu zadáme position: fixed; tak vlastne už nieje súčasťou gridu (neaplikuje sa v Gride), a je na inej vrstve. dajme tomu že bych mal grid 2×2 miežku s tým že by v prvom riadku (1,1 ;; 1,2 ;;) a v prvom stĺpci v druhom riadku (2,1 ;;) mal 3 elementy ukotvené (ako position fixed), a len element v druhom riadku v druhom stĺpci (2,2 ;;) by bol scrollovatelný? ako to v css grid spraviť?

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.