phpFashion

Na navigaci | Klávesové zkratky

Rubrika Web

Kdy používat preprocesory a kdy ne?

Složitá otázka, těžké kodérovo dilema, které se pokusím rozseknout: používejte preprocesory vždy!

Jak se Internet přesunul do mobilů, staly se největší zabijáci rychlosti načítání stránek tyhlety úhledné sloupečky:

<link rel="stylesheet" href="/css/reset.css">
<link rel="stylesheet" href="/css/content.css">
<link rel="stylesheet" href="/css/layout.css">
<link rel="stylesheet" href="/css/screen.css" media=screen>
<link rel="stylesheet" href="/css/fancybox/jquery.fancybox.css" media=screen>
<link rel="stylesheet" href="/css/print.css" media=print>
<script src="/js/jquery.js"></script>
<script src="/js/jquery.autocomplete.js"></script>
<script src="/js/fancybox/jquery.fancybox.js"></script>
<script src="/js/tooltips/jquery.tooltips.js"></script>
<script src="/js/jquery.scrollspy.js"></script>
<script src="/js/main.js"></script>

To nechceš! Chceš tohle:

<head><link rel="stylesheet" href="/assets/combined.css"></head>

<body>
...
<script src="/assets/combined.js"></script>
</body>

Taky chceš, aby se ti všechny soubory posílaly zazipované a vypadaly hutně: combined.css a hustě: combined.js.

Byly doby, kdy se komprimované skripty psaly ručně. Vynechávaly se komentáře, v JavaScriptu používaly jednopísmenné proměnné atd.

Nedělejte to. Vaším úkolem je psát čitelný kód a komprimování JavaScriptu nechte na bedrech Google Closure Compiler, který to dokáže řádově lépe než vy a navíc upozorní na chyby, o minifikaci stylů se postará například Less.

Ten dokonce zvládá vychytávku, kdy u všech miniobrázků můžete nahradit:

textarea {
    background: #fff url("img/input.gif") repeat-x;
}

za

textarea {
    background: #fff data-uri("img/input.gif") repeat-x;
}

a preprocesor je přímo vloží do combined.css, čímž odpadne hromada HTTP requestů na 100bajtové drobky.

Preprocesory prostě a jednoduše chcete!


SASS, LESS, Stylus or pure CSS? (3)

Journey into the heart of the three most known CSS preprocessors continues, though not in the way I originally planned.

CSS preprocessor is a tool that take code written in their own syntax and generates the CSS for the browser. The most popular preprocessors are SASS, LESS and Stylus. We have talked about installation and syntax + mixins. All three preprocessors have a fundamentally different way of mixins conception.

Each of them have gallery of finished mixins: For SASS there is a comprehensive Compass, the LESS has framework Twitter Bootstrap or small Elements a Stylus NIB.

… this was opening sentences of article I started write year and quarter ago and never finished. I came to the conclusion that all three preprocessors are useless. They required to do so many compromises that potential benefits seemed insignificant. Today I will explain it.

…pokračování


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.

…pokračování


Objeví Rails Dependency Injection?

Málokdo má takovou potřebu zdůrazňovat svou domnělou nadřazenost, jako právě Railisti. Abyste mě nechápali špatně, jde o dobrou marketingovou strategii. Nepříjemné je, když jí podlehnete do té míry, že zbytek světa vnímáte jen jako upachtěné kopírovače bez šance se vám někdy přiblížit. Svět takový totiž není.

Příkladem je Dependency Injection. Zatímco lidé kolem PHP nebo JavaScriptu objevili DI se zpožděním, Ruby on Rails zůstávají dosud nepolíbené. Bylo mi záhadou, proč framework s tak pokrokovou image zůstává kdesi pozadu a začal v tom pátrat. Odpověď mi dala řada zdrojů na Google nebo karmiq a zní:

Ruby je tak dobrý jazyk, že vůbec Dependency Injection nepotřebuje.

Fascinující argument, který je navíc v elitářském prostředí sebepotvrzující. A je skutečně pravdivý? Nebo jde jen o zaslepení pýchou, stejné zaslepení, jaké způsobilo nedávno přetřásané bezpečnostní díry v Rails?

Říkal jsem si, že je možné, že Ruby znám natolik málo, aby mi nějaký klíčový aspekt unikl, a že skutečně jde o jazyk, který DI nepotřebuje. Jenže primárním smyslem Dependency Injection je zřejmé předávání závislostí, aby byl kód srozumitelný a předvídatelný (a je pak i lépe testovatelný). Jenže když se podívám do dokumentace Rails na tutoriál „blog za pár minut“, vidím tam třeba:

def index
  @posts = Post.all
end

Tedy pro získání blogpostů používají statickou metodu Post.all, která odněkud (!) vrátí seznam článků. Z databáze? Ze souboru? Vyčaruje je? Nevím, protože se tu nepoužívá DI. Místo toho se tu vaří nějaké statické peklo. Ruby je bezesporu šikovný jazyk, ale DI nenahrazuje.

V Ruby lze za běhu přepisovat metody (Monkey patch; obdobně jako v JavaScriptu), což je forma Inversion of control (IoC), která třeba pro potřeby testů dovolí podstrčit jinou implementaci statické metody Post.all. Tohle ale nenahrazuje DI, kód to zřejmější neudělá, spíše naopak.

Mimochodem, zaujala mě i třída Post tím, že reprezentuje jak jeden článek na blogu, tak funguje jako repozitář (metoda all), což je porušení Single Responsibility Principle jako vyšité.

Jako odůvodnění, proč Ruby nepotřebují DI, se často odkazuje na článek LEGOs, Play-Doh, and Programming. Důkladně jsem ho pročetl, sledoval, jak autor párkrát zaměňuje „DI“ s „DI frameworkem“ (tedy něco jako zaměňovat „Ruby“ s „Ruby on Rails“) a nakonec zjistil, že k závěru, že Ruby Dependency Injection nepotřebují, vůbec nepřišel. Psal, že nepotřebují DI frameworky, jaké zná z Javy.

Jeden mylně interpretovaný závěr, pokud pohladí ego, dokáže zcela pobláznit obrovskou skupinu inteligentních lidí. Nakonec mýtus, že špenát obsahuje neobyčejné množství železa, se taky drží od roku 1870.

Ruby je velmi zajímavý jazyk, vyplatí se v něm jako v každém jiném používat DI a existují pro něj i DI frameworky. Rails je zajímavý framework, který zatím neobjevil DI. Až ho objeví, půjde o velké téma některé z příštích verzí.

(Po pokusu diskutovat o DI s Karmim, kterého pokládám za nejinteligentnějšího Railistu, nechávám komentáře uzavřené, omlouvám se.)

Viz také: Dependency injection není pouze o jednoduším testování

před rokem v rubrice Web | shlédnuto 15100×


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

Vyplatí se používat CSS preprocesory? A pokud ano, který zvolit? Pokračuji v rozboru tří nejznámějších konkurentů.

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. Mají řešit praktické nedostatky samotného CSS.

předchozí části jsme si ukázali, jak preprocesory nainstalovat. Dnes se jim podívám na zoubek.

Syntaxe

Ač jednotlivé nástroje používají odlišnou syntax, všechny rozumí klasickému CSS. To je nesmírně důležité! Můžete kopírovat existující CSS fragmenty a budou fungovat. Ačkoliv…

SASS používá dvě různé syntaxe, jedna se nazývá SASS (stejně jako preprocesor), nepoužívá středníky ani složené závorky {} a místo toho odsazuje mezerami či tabulátory:

// SASS
#main
    color: blue
    font-size: 0.3em

Druhou syntaxí je SCSS, která vypadá jako klasické CSS a měla být i plně kompatibilní (budu ji pro SASS používat v dalších příkladech). Stejnou syntax má i LESS:

// SCSS, LESS a CSS
#main {
    color: blue;
    font-size: 0.3em;
}

Stylus také rozumí CSS syntaxi, nicméně upozorňuje, že nejde o 100% kompatibilitu, především proto, že hodně bazíruje na odsazování. V jeho syntaxi lze vynechat složené závorky, středníky a dokonce i dvojtečky:

// Stylus
#main
    color blue
    font-size 0.3em

Ale pozor! Důležité je, že tyto znaky můžeme vynechat. Pokud vám zápis připadá příliš hutný, klidně si dvojtečky doplňte. Nechcete odsazovat? Vražte tam složené závorky. Velmi podobně funguje NEON. V tomto se zásadně liší od úsporné SASS syntaxe, kde vynechání závorek a středníků je povinnost. Což ji činí z praktického hlediska nepoužitelnou a chápu, proč tvůrci o kompatibilitu s CSS usilovali, ale udělali to nešťastně zavedením další, nekompatibilní, ukecané syntaxe SCSS.

Když už se totiž rozhodnu preprocesor používat, ocením, když mi zjednoduší i syntaxi (alespoň nepovinné středníky), což bohužel umí jen Stylus. Jeho syntax je nejpružnější a nejúspornější.

V kontrastu přísnosti LESS a SASS je zajímavé, že všechny tři preprocesory podporují // řádkové komentáře.

Když udělám chybu

Pokud uděláte v dokumentu chibu, preprocesory vás na ni upozorní chybovou hláškou. A v tomto směru se jednotlivé nástroje zásadně liší. Pokud třeba zapomenu ve výše uvedeném kódu uzavírací }, oznámí SASS:

Syntax error: Invalid CSS after "font-size: 0.3em;": expected "}", was ""
        on line 4 of test.scss

Stylus:

if (err) throw err;
               ^
ParseError: stdin:4
1| #main {
2|   color: blue;
3|   font-size: 0.3em;
> 4|

unexpected "eos"

a LESS:

ParseError: missing closing `}` in test.less:9:17
8
9 unexpected "eos"undefined

Nutno dodat, že LESS měl šťastnější chvilku. Pokud bych zapomněl středník, skončí to u obvyklejšího

ParseError: Syntax Error on line 2 in test.less:2:1
1 #main {
2       color: blue
3       font-size: 0.3em

Výmluvné chybové hlášky jsou pro mě důležité a v tomto směru s přehledem vede SASS. Ačkoliv se to z ukázky tak nejeví, hodně se snaží i Stylus. Běžně však špatně spočítá číslo řádku a hlásí chybu o pár řádků výš, než skutečně je. LESS se nejčastěji zmůže na nicneříkající Syntax Error on line XY.

Občas jsem narážel na chyby v samotném preprocesoru. Pokud se mi je podařilo izolovat, snažil jsem se je nahlásit (LESS, Stylus), ale ne vždy to šlo. Zde se nejvíc projevila vyspělost jednotlivých nástrojů. Zatímco nejstarší SASS se mi z rovnováhy nepodařilo vyvést nikdy, druhé dva nástroje obsahují chyb bohužel požehnaně.

Co všechno umí?

Drtivou většinou užitečných vychytávek najdeme u všech tří nástrojů, byť třeba nemusí být uvedeny v dokumentaci. V množství asi vede SASS, ale takto se to hodnotit nedá. Třeba nested properties nepotřebuji, naopak property lookup a generátor data URI ve Stylusu vypadá užitečně. Tedy do chvíle, než zjistíte, že převádí buď všechny obrázky, nebo žádný.

Nechci sepisovat výčet jednotlivých vlastností ani srovnávat jejich zápis, to najdete v dokumentaci nebo ve srovnávacím článku na NetTuts. Zaměřím se místo toho na fundamentální rozdíly a největší z nich se týkají tzv. mixinů.

Mixiny

Mixiny jsou z mého pohledu nejdůležitější vychytávkou preprocesorů, protože mění způsob, jak píšeme HTML kód. Vysvětlím. Asi nejznámější „mixin“ je tzv. clearfix, která se stará o to, aby z bloku nevytékaly plovoucí prvky. Obvykle vypadá nějak takto:

.clearfix:after {
    clear: both;
    content: ".";
    display: block;
    height: 0;
    visibility: hidden;
    font-size: 0;
}

(Poznámka: existují jednodušší i složitější varianty clearfixu. Kupodivu mně vždycky fungovalo nastavit bloku overflow: auto a clearfix jsem nepotřeboval. Ale v tuto chvíli jde jen o příklad.).

Clearfix pak aktivujeme v HTML:

<div id="content" class="clearfix">
    <div style="float: left;">....</div>
    ...
</div>

Ale to neděláš dobře, Jaromíre. Clearfix by se měl aplikovat na straně stylů, přímo pro #content, nikoliv v HTML. Jenže komu by se chtělo kazit si krásný stylopis kopírováním ošklivého hacku? Mnoho kodérů raději sáhne do HTML.

S preprocesory však netřeba nic kopírovat a vystačíme si s jedinou instrukcí. Nejprve si clearfix uložíme jako tzv. mixin a poté ho v definici #content zavoláme:

SASS:

// definice mixinu (zkráceno)
@mixin clearfix {
    &:after { clear: both; ... }
}

#content {
    @include clearfix; // vložení mixinu
}

LESS:

.clearfix() {
    &:after { clear: both; ... }
}

#content {
    .clearfix;
}

Stylus:

clearfix()
    &:after { clear: both; ... }

#content
    clearfix()

Zmizí tak nutkání zasahovat do zdrojového kódu. A to je velmi důležité.

Jak vidno, syntaxe SASS je opět nejukecanější. Za zmínku stojí, že LESS umožňuje volat jako mixin i jakoukoliv třídu nebo ID.

Parametrické mixiny

Ještě zajímavější je to ve chvíli, kdy mixinům předáme parametry:

SASS:

@mixin border-radius($arg) {
    -webkit-border-radius: $arg;
    -moz-border-radius: $arg;
    border-radius: $arg;
}

#content {
    @include border-radius(2px);
}

LESS:

.border-radius(@arg) {
    -webkit-border-radius: @arg;
    -moz-border-radius: @arg;
    border-radius: @arg;
}

#content {
    .border-radius(2px);
}

Stylus:

border-radius(arg)
    -webkit-border-radius: arg
    -moz-border-radius: arg
    border-radius: arg


#content
    border-radius(2px)

Ve Stylusu můžeme použít i zapis s dvojtečkou:

#content
    border-radius: 2px

Což je velmi zajímavé! Když totiž později vendor prefix odstraníme, nebo když naopak zjistíme, že určité vlastnosti potřebujeme vendorovou variantu dodat, nemusíme změnit ani čárku v samotném stylu. Wow.

Jenže… co když mixin zavoláme s více parametry? Například uvedeme border-radius: 2px 3px. Překvapivě Stylus bude 3px v tichosti ignorovat. Proč tomu tak je?

V CSS existují dva způsoby, jak uvést více argumentů, lišící se v oddělovači:

  • oddělené mezerama: border: 1px solid black
  • oddělené čárkama: rgb(10, 20, 30)

Totéž se rozlišuje i v preprocesorech. Ve Stylusu platí, že volání mixinu border-radius: 2px 3px je ekvivalentní k border-radius(2px, 3px) (a dává mi to smysl), obojí představuje předávní dvou argumentů. Naopak border-radius(2px 3px) bez čárky předává argument jeden. Náš mixin očekává pouze jeden parametr a druhý tiše bez jakéhokoliv varování zahodil. Oprava spočívá v použití užitečného klíčového slova arguments namísto předaného argumentu arg.

SASS a LESS naopak předání více argumentů, než je mixinem očekáváno, vnímají jako fatální chybu. V případě SASS to v důsledku vede k podivným blokům $shadow-1, …, $shadow-10 patrným v galerii Compass, zatímco LESS se s problémem snaží vypořádat konstrukcí when(). Nic z toho mi nepřipadá ideální.

Pokračování zase příště.