Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

SASS, LESS, Stylus nebo čisté CSS? (3)

Cesta do nitra tří nejznámějších CSS preprocesorů pokračuje, i když ne tak, jak jsem původně plánoval.

CSS preprocesor je nástroj, který vám ze zdrojového kódu zapsaného ve vlastní syntaxi vygeneruje CSS pro prohlížeč. Mezi nejznámější patří SASS, LESS a Stylus. Ukázali jsme si, jak je nainstalovat a naťukli téma syntaxe a mixinů. Všechny tři preprocesory nabízejí fundamentálně rozdílný způsob, jak programovat s mixiny. Každý je v tom jinak konzistentní a každý umí být jinak matoucí.

Pro každý preprocesor existuje galerie hotových mixinů, do kterých nahlédněte přinejmenším k posouzení jejich srozumitelnosti. Pro SASS existuje komplexní Compass, LESS má framework Twitter Bootstrap nebo drobné Elements a Stylus NIB.

…tak takhle začínal článek, který jsem rozepsal před rokem a čtvrt a nikdy nedokončil. Přišel jsem totiž k závěru, že všechny tři preprocesory jsou, alespoň zatím, nepoužitelné. Jejich nasazení by představovalo tolik ústupků, že by se vedle nich potenciální výhody dočista ztrácely. Dnes to vysvětlím.

CSS preprocesor není věc, se kterou bych začínal na zelené louce. Nejsem úplný nováček, s kaskádovými styly mám 10letou historii, kdysi mě mocně nakopl Pixy a dnes mám celkem vypilovaný systém, do kterého potřebuji preprocesor zasadit. Jak ten systém vypadá? Podle mého nejde o vůbec nic neobvyklého.

Když se podíváte pod pokličku třeba tohoto blogu, zjistíte, že se ze serveru načítá právě jeden CSS soubor a právě jeden JS, oba minimalizované. Přičemž onen soubor combined.css obsahuje styly pro všechna zařízení, tj. obrazovku, tiskárnu, mobily, retinu atd. Nezkomprimovaný vypadá nějak takto:

@import "http://fonts.googleapis.com/css?family=Open+Sans:400&subset=latin,latin-ext";

@import "libs/reset.css";
@import "libs/classes.css";

@import "libs/fshl.css" screen;
@import "fancybox/jquery.fancybox.css" screen;
@import "layout.css" screen;
@import "homepage.css" screen;

@import "libs/print.css" print;
@import "print.css" print;

Celý stylopis je tedy rozdělený do řady menších jednotek. V adresáři libs se skrývá drobný CSS framework definující základní pravidla, která používám na všech projektech (btw reset.css není prasárnička á la Eric Meyer’s reset, spíš něco takového), dále tu jsou styly použitých komponent a vůbec celého projektu. Většina importů uvádí závislost na médiu, takže se aplikují jen pro tiskárnu či obrazovku.

V samotných souborech rád používám odsazování, které mi zásadně zvyšuje čitelnost:

a {
    padding: 3px;
    margin: 0 -3px;
    text-decoration: none;
}

    a:hover, a:active, a:focus {
        color: white;
        background-color: blue;
    }



article {
    margin: 2em 0;
}

    article hr {
        visibility: visible;
        clear: none;
    }

    article footer {
        margin-top: 2em;
    }

Musím zdůraznit, že tohle všechno je normální CSS 2.0, které správně zobrazí jakýkoliv prohlížeč. Jediná podmínka je, že pravidla @import musí být uvedena na začátku souboru před čímkoliv jiným. Přičemž uvnitř inkludovaných souborů lze klidně vkládat další (to moc nedělám) a nebo uvádět media queries, pomocí kterých doladím podobu pro mobily nebo nasadím obrázky ve vyšším rozlišení pro displeje retina (prohlížeč správně kombinuje media query v souboru s médiem uvedeným u importu).

Celou strukturu by bylo možné sakumprásk nahrát na server a normálně by to fungovalo. Udělal jsem si ale jednoduchou funkci, která všechny ty klauzule @import expanduje do jediného souboru, ten ještě zkomprimuje a teprve poté pošle na server. Má to zásadní vliv na rychlost načítání stránek, obzvlášť, pokud je čtete v metru.

A do tohoto systému jsem chtěl přivést CSS preprocesor, od kterého jsem si sliboval, že samozřejmě převezme úlohu sestavení výsledného stylu, a dovolí mi lépe řešit některé ošidnosti CSS.

Jak jsem byl bláhový!

Aby preprocesor @importované soubory vůbec zpracoval, je třeba jejich příponu změnit z .css na proprietární (tj. .less, .scss, .sass nebo .styl). Jistě, je zcela správné používat proprietární přípony, jen mi o to, že preprocesor si neporadí také s CSS souborem, přičemž stačí jej pouze přejmenovat a hned to jde.

Najednou koukám, že se mi ztratily některé obrázky. Proč? Například jquery.fancybox.css obsahuje definici background-image: url('fancybox_sprite.png'), přičemž oba soubory se nachází v podadresáři fancybox. Když zkombinujeme styly z různých podadresářů do jednoho souboru, pochopitelně musíme transponovat všechny relativní cesty. To dá selský rozum. Chová se tak samozřejmě i prohlížeč, když vyhodnocuje @import, dělá to i zmíněná 15řádková los stupidos funkce v FTP deploymentu, jen preprocesory, ty to neumí a soubor jednoduše zkriplí. Vážně :-(

Hlavně jsem nepřišel na způsob, jak tuhle kulervoucí vadu obejít. Udělat si bordel ve složce a všechny obrázky nahrát do kořenového adresáře? Modifikovat cesty ve stylech? Ve stylech třetích stran? Naprogramovat prepreprocesor? Čím tyhle ústupy preprocesor vyváží?

Jenže tím zoufalství zdaleka nekončí…

CSS preprocesory si neporadily ani s media queries u pravidel @import:

@import "fancybox/jquery.fancybox.css" screen;

Je třeba screen odstranit a celý obsah vkládaného souboru obalit do @media screen { ... } (neplatí pro SASS, ten sice taky nerozumí mediu v pravidle @import, ale zvládá opis @media screen { @import "style.css" }). Krom toho, že fakt nechci modifikovat soubory natož třetích stran, protože to komplikuje budoucí aktualizace, nemusí jít o nikterak triviální úpravu. Zrovna zmíněný fancybox.css obsahuje @media queries pro retinu a otázkou je, jak se s jejich zanořením preprocesor vypořádá. Pohořely na tom všechny.

A to stále není všechno!

Klíčové je, aby preprocesor dokázal schroustat mé existující CSS (jimž jsem byl donucen změnit příponu). Žádné prasárny ve stylech nepoužívám, SASS i LESS se sekly jen na rovnítku =padding: 0 (LESS ležérně chybu ohlásil na docela jiném řádku), což je obdoba legendárního podtržítkového hacku pro IE6 ve verzi pro IE7. Kašlat na IE7, tohle jedno pravidlo jsem smazal a vše fungovalo.

Ne tak v případě Stylusu (a přiznávám, že tomuto nástroji jsem nadržoval). Ten se sesypal na mém oblíbeném odsazovaní. Prohlásil unexpected "indent" a bylo zalíčené. Stačí běžný komentář a Stylus odchází plakat do kouta.

Přátelé, abych mohl nasadit CSS preprocesor, musel bych totálně dokurvit čistou adresářovou strukturu a drasticky modifikovat své styly i styly třetích stran. Abych mohl vychutnat mixínek? Ne, děkuji, to vážně ne :-)

A to nemluvě o zabugovanosti dvojice LESS a Stylus, dokonce Stylus ani neumí pravidlo @import přehodit na začátek souboru a generuje nevalidní CSS. Smutné. (Prosím, nepište mi, že vy preprocessor používáte a všechno vám funguje, je to stejně hloupé, jako kdyby vás doktor odmítl se zlomeninou nohy s tím, že jeho noha vůbec nebolí.)

O rok a čtvrt později

Tohle se odehrálo před rokem a čtvrt. Hodně dlouhá doba ve vývoji žhavých technologií. Chyby jsem tehdy nahlásil a dnes se podíval, co je u našich tří kamarádů nového.

  • SASS udržuje sassus quo, všechny zmíněné nedostatky i přednosti setrvávají.
  • Stylus? Těžké zklamání, naučil se sice řešit relativní cesty při uvedení parameteru -r, ale žádný bug nebyl vyřešen a autor na něj nemá čas.
  • LESS. Před rokem největší outsider mi dnes vyrobil perfektní CSS. Poradil si se vším. Wow!

LESS mi udělal obrovskou radost! Ano, nepoužil jsem žádné pokročilé funkce a jen se raduji z toho, že rozumí CSS alespoň tak, jako IE6, dokáže vygenerovat při uvedení parametru -ru sloučený soubor se správnými cestami k obrázkům, soubory není třeba přejmenovávat díky @import (less) "file.css" a mohu jej proto neskutečně snadno nasadit i do existujícího projektu a začít využívat všech výhod preprocesorů. Ty léta náročného vývoje nepřišly nazdar!

HAPPY END.

Komentáře

  1. v6ak http://v6ak.com #1

    K těm knihovnám: Nemám s tím nějaké velké zkušenosti, ale používal jsem trochu CompLESS a vypadá, že je o trochu bohatější než Elements.

    před 3 lety | odpovědět | reagoval [6] v6ak
  2. David Grudl http://davidgrudl.com #2

    avatar

    CSS preprocesory: Nejspíš nějaký potřebujete a nejspíš je to LESS – skvělá reakce od Martina Michálka, moc se mi líbí přirovnání ke Gitu.

    Jen dodám, že mám připravený materiál ještě pro jeden článek, kterou celou věc uchopí z docela jiného konce.

    před 3 lety | odpovědět | reagoval [6] v6ak
  3. riki #3

    avatar
    před 3 lety | odpovědět | reagoval [6] v6ak
  4. Martin Michálek http://www.vzhurudolu.cz #4

    avatar

    Davide, ještě na vysvětlení, proč tvé požadavky na preprocesor považuji za nestandardní. :)

    Obecně vzato — nestandardní je scénář, ve kterém chceš preprocesorem zpracovat existující CSSko. Ke všemu CSSko, které s nadsázkou používá oldskul postupy. ;)

    Preprocesor považuji za jiný jazyk s odlišnou filozofií a naprosto odlišným způsobem práce. Kóderské návyky při práci s preprocesorem jsou jiné než při práci s CSSkem.

    Konkrétně…
    Ad. jiné koncovek souborů (.css vs .less): — Ve smyslu výšeuvedeného nemůže na preprocesor fungovat zvýrazňovač syntaxe z CSS a potřebuješ odlišit zdrojáky od zkompilovaných CSS souborů. Odlišení koncovek je existenční nutnost.

    Ad. cesty k obrázkům při importování jquery.fancybox.css — Fancybox má být (a jednou snad bude) konfigurovatelná LESS komponenta. Ve tvém postupu se míchá starý a nový svět front-endu. Se starými CSSky třetích stran to zatím bohužel nelze jinak a je potřeba to nějak obcházet.

    Ad. rovnítkový hack — on někdo dneska používá CSS hacky? :) Pro detekci IE máme podmíněné komentáře, ne? Preprocesory s tím nepočítají, protože speciální znaky používají pro něco jiného.

    před 3 lety | odpovědět | reagoval [5] v6ak [7] David Grudl
  5. v6ak http://v6ak.com #5

    #4 Martine Michálku, Celkem souhlas, tak ze 2/3, možná 3/4. Používat zvýrazňování (a napovídání apod.) CSS pro LESS je hack podobný používání přípony phtml pro šablony Latte. Ono to bude lepší než plaintext, ale nebude to úplně ono. Pokud už chci tento hack použít, můžu si nastavit svůj editor a nekomplikovat tak (zvlášť u týmového projektu) rozlišování CSS a LESS (případně PHP a Latte) ostatním členům týmu. Nebo i sobě při změně editoru/IDE.

    Nebudu ale moc souhlasit s tím, že jquery.fancybox.css apod. nemá preprocesor řešit. Považuji za standardní požadavek reálného světa, aby šlo pracovat i s ostatními CSS soubory. Pokud bude Fancybox standardní konfigurovatelná LESS komponenta, pak fajn. Ale co kdyby se autor rozhodl raději použít např. SASS? Pak by LESS IMHO mělo umožňovat zpracovat výsledné CSSko. (Neříkám, že by mělo umět zkompilovat SASS, i když by to byl možná zajímavý bonus.)

    před 3 lety | odpovědět | reagoval [8] Martin Michálek
  6. v6ak http://v6ak.com #6

    Budu trochu OT. #2 David Grudl mohl bych se zeptat, jak funguje tady to skloňování jmen a příjmení? Je to vlastní práce, nebo nějaká knihovna? Jak to funguje na přezdívky jako #1 v6ak a #3 riki?

    před 3 lety | odpovědět
  7. David Grudl http://davidgrudl.com #7

    avatar

    #4 Martine Michálku, asi jsem nebyl dostatečně srozumitelný, pokusím se to napravit. Nejprve musím citovat http://sass-lang.com/

    The most commonly used syntax is known as “SCSS” (for “Sassy CSS”), and is a superset of CSS3’s syntax. This means that every valid CSS3 stylesheet is valid SCSS as well. SCSS files use the extension .scss.

    To je nesmírně důležitá věc, v podstatě říká: nasaď SASS do svého existujícího workflow a budeš sklízet jen výhody. Podobně se tváří i ostatní systémy, byť neslibují 100% kompatibilitu „Stylus: So although not every plain-CSS stylesheet will work with zero modification, this feature allows those who prefer CSS syntax to continue doing so while leveraging Stylus’ other powerful features.“

    Vezmu to od konce: rovnítkový hack jsem zmínil jako to jediné, čemu SASS a LESS neporozuměl, tedy ve smyslu „super, stylům rozumí perfektně!“ Ovšem LESS má problém s číslováním řádků, když hlásí chybu, a Stylus je mimo hru úplně, protože si vyseká zuby na pouhém odsazení.

    ad koncovky: je zcela správné, že systémy používají vlastní koncovky (ale máš pravdu, že z článku to blbě vyznělo). Kritizuji tady pouze a jen funkci @import, která se jinak chová k souborům s příponou CSS a jinak k vlastním (nebo bez přípony, což je další zrůdnost). Tohle mělo být rozlišeno jinak, abych nemusel, když jsi CSS (tedy, subset SCSS, tedy SCSS s příponou CSS) vložit, měnit souboru příponu cílového souboru, ale například rozlišovat chování syntaxí @import url(file.css) vs hypotetické @import inline("file.css").

    A s funkcí @import souvisí i relativní cesty k obrázkům. Zkrátka preprocesory se chovají (chovaly) jinak, než CSS, než prohlížeč, než velí zdravý rozum a tohle vidím jako jednoznačnou chybu. Skutečně mě nenapadá scénář, kdy by mělo netransponování relativních cest výhodu.

    Říkáš „ Se starými CSSky třetích stran to zatím bohužel nelze jinak a je potřeba to nějak obcházet.“ – Tomu vůbec nerozumím, v tomhle asi tkví rozdíl našeho vnímání světa. Vidím to totiž spíš jako: „A proč by to nešlo jinak?“ :-) Že má preprocesor nějaký nedostatek či chybu není důvod složit ruce do klína a říct – nejde to. Tady není žádný starý a nový svět, tady je CSS, do jehož světa přicházejí nástroje, které nám mají sloužit, nikoliv vytvářet vlastní problémy. CSS není oldskul a jeho používání nestandardní scénář, CSS je základ.

    Nakonec LESS zmíněné chyby opravil a ono už to najednou jde. Proto jsem ho začal předevčírem používat.

    (Btw, přemýšlel jsi někdy nad tím, proč výkladní skříň preprocesoru framework Twitter Bootstrap pro označení třeba tlačítek používá dvojici tříd btn btn-primary, když btn-primary by klidně mohlo btn přimixovávat?)

  8. Martin Michálek http://www.vzhurudolu.cz #8

    avatar

    #5 v6aku, #7 David Grudl Ještě obšírněji k ne-transponování url při importování CSSka třetí strany: vidím to tak, že všechny preprocesory při zpracování vlastních importů (tedy souborů .less, .scss nebo .styl) konzistentně říkají, že root adresář pro cesty k obrázkům pro url(…) je ten, ve kterém bude vygenerované .css. Když přejmenuješ jquery.fancybox.css na jquery.fancybox.less, říkáš tím preprocesoru, že souhlasíš a že budeš hrát jeho hru.

    Pokud bys jej nepřejmenoval a importoval jquery.fancybox.css, což je myslím správnější řešení (proč v adresáři třetí strany vytvářet další soubory?), preprocesor ti ve výsledném CSS vygeneruje běžný „CSS @import“. To je myslím OK.

    V tom přejmenování vidím ten střet „starého“ a „nového“ z původního komentáře.

    Běžný „CSS @import“ ti vadí, protože vytváří request navíc a nekomprimuje importované CSS? Pak bys měl vygenerované CSS prohnat nějakým buildovacím procesem, který CSSka spojí a minifikuje.

    Osobně preprocesor nevnímám jako buildovací nástroj. Kód, který mi generuje, potřebuji na lokální mašině co nejpřehlednější — tzn. ne-minifikovaný, s komentáři atd.

    před 3 lety | odpovědět | reagoval [10] David Grudl
  9. Martin Michálek http://www.vzhurudolu.cz #9

    avatar

    #7 Davide Grudle, (Btw, přemýšlel jsi někdy nad tím, proč výkladní skříň preprocesoru framework Twitter Bootstrap pro označení třeba tlačítek používá dvojici tříd btn btn-primary, když btn-primary by klidně mohlo btn přimixovávat?)

    Kvůli dokumentace. :) Jako autor si můžeš samozřejmě vybrat, jestli použiješ mixin nebo třídu v HTML. Bootstrap dokumentace je zaměřená i na typy autorů, kteří moc nechtějí sahat do CSSka nebo JS souborů.

    před 3 lety | odpovědět | reagoval [10] David Grudl
  10. David Grudl http://davidgrudl.com #10

    avatar

    #8 Martine Michálku, myslím, že se dostáváme k jádru věci. Běžný CSS import není jen taková lecjaká věc – musí se nacházet úplně na začátku stylu. S jeho umístěním v rámci celého stylopisu máme tedy značně svázané ruce. Přičemž pořadí je podstatné pravidlo kaskádovosti. Jinými slovy, preprocessor se nemůže zříci funkce buildovacího nástroje, je to naopak dosti klíčový úkol (a vůbec nejde o minifikaci, ta je jen příjemným bonusem). Pokud buildování nezvládne dobře, zasadit jej do existujícího workflow se stává noční můrou.

    #9 Martine Michálku, můžeš to prosím rozvést, úplně jsem tě nepochopil. Konkrétně třeba proč .btn-primary v sobě už neobsahuje .btn.

  11. Inza http://www.juicymo.cz #11

    avatar

    WOW, jak to tak čtu, tak si říkám: „Zlatá asset pipeline v RoR…“ ;)

    A jen jeden dotaz Davide: Jak s tím svým výsledným jedním CSS souborem řešíš mobile first – tedy třeba to, že např. vůbec nechci stahovat v mobilu CSS styly pro desktop?

    před 3 lety | odpovědět | reagoval [12] David Grudl
  12. David Grudl http://davidgrudl.com #12

    avatar

    #11 Inzo, u webů, které dělám, není ve velikosti celého zazipovaného stylu a části pro mobily takového rozdílu, aby mělo smysl se tím zabývat.

    před 3 lety | odpovědět
  13. Martin Michálek http://www.vzhurudolu.cz #13

    avatar

    #10 Davide Grudle, K CSS @importům — problém s pořadím samozřejmě může nastat, ale potřeboval bych reálný příklad. Moje fantazie se tady ukázala jako nedostatečná. :)

    K .btn a .btn-primary v Bootstrapu — Už se chytám. :) Důvod je udržovatelnost LESS/CSS kódu. Představ si, že těch variací .btn potřebuješ u tlačítka víc: .btn .btn-primary .btn-large .btn-block. Ještě si představ, že každá variace přimixovává původní .btn. A teď si představ vygenerovaný CSS kód. :) Bude to pořádný sloupec deklarací, navíc teoreticky plných konfliktů ve specifičnosti. Teoreticky proto, že zrovna u tlačítek to platit nemusí, ale při spravování komplexního kódu kategorie Bootstrap by se to určitě projevilo.

  14. Peter Kahoun http://kahi.cz #14

    avatar

    #10 Davide Grudle, #13 Martin Michálek Ne teoreticky, ono by to u tlačítek s 2+ btn-třídami nefungovalo prakticky. Ale do budoucna by pro Bootstrap bylo řešením .btn abstrahovat jako [class^=„btn-“] (pak není nutno ji ani jmenovat v HTML, ani extendovat v CSS).

    před 3 lety | odpovědět | reagoval [15] v6ak
  15. v6ak http://v6ak.com #15

    #14 Petere Kahoune, Což je celkem hnus, protože:

    1. To patrně nejde používat v mixinech. Nemusím mít pro každé tlačítko class="btn", mohu to přimixovat i do jiných tříd, identifikátorů apod.
    2. Co třeba class="foo btn-primary"?
    před 3 lety | odpovědět
  16. David Grudl http://davidgrudl.com #16

    avatar

    #13 Martine Michálku, Příkladem je třeba:

    @import "screen.less";
    @import "fancybox/jquery.fancybox.css";

    Preprocesor první soubor fyzicky vloží, kdežto u druhého vygeneruje běžný CSS @import. Tím je ale výsledek nevalidní, neboť před pravidlem import nesmí být CSS styl. Řešením je buď obrátit pořadí, což nejde, protože tím se mění význam, nebo souboru (třetí knihovny) přejmenovat koncovku, což prudí.

    Jinými slovy, preprocesor by měl (třeba pomocí klíčového slova inline, nevím) dát možnost naimportovat CSS soubor stejně, jako importuje soubory své.

    před 3 lety | odpovědět | reagoval [17] Ondřej Kubíček
  17. Ondřej Kubíček http://www.kubon.cz #17

    avatar

    #16 Davide Grudle, co použít import options? tím se ti css soubor vloží přímo jako by to byl less soubor

    http://lesscss.org/features/#…

    @import "screen.less";
    @import (less) "fancybox/jquery.fancybox.css";
    před 3 lety | odpovědět | reagoval [18] David Grudl
  18. David Grudl http://davidgrudl.com #18

    avatar

    #17 Ondřeji Kubíčku, ano, tohle je jedna z těch milých vlastností, díky kterým jsem nadšeným uživatelem LESS.

    před 3 lety | odpovědět

Zanechat komentář

Text komentáře
Kontakt

(kvůli gravataru)



*kurzíva* **tučné** "odkaz":http://example.com /--php phpkod(); \--