Sass Guidelines
Umíněný průvodce pro psaní rozumného, udržovatelného a škálovatelného Sass.
You are viewing the Czech translation by Honza Bittner of the original Sass Guidelines from Kitty Giraudel.
This version is exclusively maintained by contributors without the review of the main author, therefore might not be completely authentic, especially since it is currently in version 1.1 while the English version is in version 1.3.
Přispívání
Sass Guidelines je můj volnočasový projekt. Snad ani není potřeba dodávat, že udržovat všechno aktuální, zdokumentované a relevantní dá docela dost práce. Samozřejmě už jen toho, že je pro vás tento manuál přínosem, si velice cením!
Pokud byste rádi chtěli přispět, budu rád za jakýkoliv tweet, či jinou metodu šíření, ale i třeba za upozornění na chybu otevřením issue nebo pull-requestu na GitHub repositáři.
V neposlední řadě, než začneme: pokud se vám tento dokument líbil, nebo pro vás byl užitečný, zvažte, prosím, jeho podporu!
O Sassu
Takto je Sass popisován v jeho dokumentaci:
Sass je CSS rozšíření, které dodává sílu a eleganci základnímu jazyku.
Hlavním cílem Sassu je opravit nedostatky v CSS. CSS, jak všichni víme, není nejlepší jazyk světa [nutná citace]. I když je velmi jednoduchý na naučení, mžiknutím oka se může stát chaotický, zejména pokud jde o velké projekty.
A to je přesně ten moment, kdy se hodí mít po ruce Sass, jako meta-jazyk, který vylepšuje CSS syntaxi za pomoci různých funkcí a šikovných nástrojů, a to vše konzervativně k jazyku CSS.
Nejde ale o to, proměnit CSS do plnohodnotného programovacího jazyka, jelikož Sass chce jenom pomoci tam, kde CSS selhává. A právě proto není začít se Sassem o nic těžšího, než-li se začít učit CSS: jednoduše to přidává několik funkcí navíc.
Jak již bylo řečeno, existuje mnoho způsobů využití těchto funkcí. Některé jsou dobré, některé špatné a některé poměrně neobvyklé. Tenhle manuál si klade za cíl nastínit vám konzistentní zdokumentovaný přístup pro psaní Sassu.
Další četba:
Ruby Sass nebo LibSass
První commit Sassu se datuje na konec roku 2006, tedy skoro před 8 lety. Netřeba snad ani dodávat, že od té doby uplynula dlouhá doba. Při počátečním vývoji v Ruby se tu a tam objevil nějaký ten port. Nejúspěšnější z nich, LibSass (napsaný v C/C++) je nyní blízko k plné kompatibilitě s původní Ruby verzí.
V roce 2014 se Ruby Sass a LibSass týmy se rozhodly počkat a sjednotit obě verze před dalším postupem. Od té doby LibSass aktivně uvolňuje verze kompatibilní s jeho starším bratrem. Poslední zbývající nesrovnalosti jsem osobně zaznamenal ve svém projektu Sass-Compatibility. Pokud víte o nějakém rozdílu mezi verzemi, který v seznamu není uvedený, budu vám vděčný za otevření příslušné issue.
Vraťme se zpět k volbě kompilátoru. Ono to vlastně záleží na vašem projektu. Pokud je založen na Ruby on Rails, je lepší použít Ruby Sass, který se na takovýto případ perfektně hodí. Také mějte na paměti, že Ruby Sass bude vždy referenční implementací a bude vždy udávat směr funkcí LibSassu. Na projektech, které Ruby nevyužívají, bude použití LibSassu pravděpodobně lepší nápad, jelikož je pravděpodobně už je wrapper pro daný jazyk vytvořen. Takže pokud chcete použít například Node.js, node-sass je jasná volba.
Další četba:
Sass nebo SCSS
Ohledně sémantiky jména Sass je hodně nejasností, a to z dobrého důvodu: Sass označuje jak preprocessor, tak i jeho vlastní syntaxi. To není moc příhodné, co?
No, Sass zpočátku popsal syntaxi, jejímž charakteristickým rysem bylo založení na odsazení. Brzy poté se vývojáři Sass rozhodli uzavřít propast mezi Sassem a CSS poskytnutím CSS-friendly syntaxe nazývané SCSS podle Sassy CSS. Jejím motem je: pokud to je validní CSS, je to validní SCSS.
Od té doby je Sass (myšleno preprocesor) poskytován ve dvou rozdílných syntaxích: Sass (bez kapitálek, prosím), také známou jako odsazovaná syntaxe, a SCSS. Kterou z nich budete používat je v podstatě jen a jen na vás, jelikož obě jsou striktně ekvivalentní co se funkcí týče. Je to jen otázka osobního vkusu.
Na mezery citlivá syntaxe Sass spoléhá na odsazení, zbavení se závorek, středníků a dalších interpunkčních symbolů, což vede ke štíhlejší a kratší syntaxi. Oproti tomu SCSS je jednoduší na naučení, jelikož je to spíše něco málo navíc oproti CSS.
Já osobně preferuji SCSS nad Sass, protože je blíže k CSS a je přátelštější k většině vývojářů. Proto je také SCSS výchozí syntaxí v tomto manuálu. Můžete přepnout na Sass odsazenou syntaxi v .
Další četba:
Další preprocesory
Sass je preprocesor jako každý jiný. Jeho největší soupeř je LESS. Preprocesor založený na Node.js a který se stal poměrně populárním díky proslulému CSS frameworku Bootstrap, který jej využívá. Je tu také Stylus, což je tak trochu hloupá neomezená verze LESS, kde můžete dělat v podstatě co jen chcete, protože skoro dělá z CSS programovací jazyk.
Proč zvolit Sass nad LESS nebo jiným preprocesorem? je dnes stále hojně pokládaná otázka. Ne tak dávno jsme doporučovali Sass pro projekty založené na Ruby, protože to byl první vytvořený v Ruby a dobře se používal s Ruby on Rails. Nyní, když LibSass skoro dohnal originální Sass to již není až tak relevantní rada.
To co zbožňuji na Sassu je jeho konzervativní přístup k CSS. Sass je navrhnut na základě silných zásad: mnoho z designového přístupu přichází čistě z víry klíčového týmu, že a) přidávání fuknce navíc má komplexní cenu, která musí být odůvodněna užitečností a b) by mělo být jasné co daný blok stylů dělá pouze při pohledu z tohoto bloku. Sass také klade mnohem větší důraz na detaily než ostatní preprocesory. Pokud je mi známo, klíčoví designéři se hluboce starají o podporu každého koutového případu CSS kompatibility a starají se o to, aby bylo každé obecné chování konzistentní.
Jinými slovy, Sass není preprocesor zaměřen na hloupoučké rádoby programátory, jako mě, přidáním mimořádné funkce na vrcholu jazyka, který není určen na podporu logických případů použití. Je to software zaměřený na řešení aktuálních problémů a pomoci poskytnout užitečné funkce pro CSS kde CSS zaostává.
Preprocesory stranou, měli bychom také zmínit postprocesory, které obdržely v několika posledních měsících významné boom. A to především díky PostCSS a cssnext. Postprocesory jsou do značné míry rovnocenné k preprocesorům až na to, že neposkytují nic jiného než CSS syntaxi zítřka.
Můžete je brát jako polyfill pro nepodporované CSS funkce. Například kdybyste psali proměnné tak, jak je popsáno v CSS specifikaci, poté zkompilovali své styly pouze postprocessorem, abyste našli každou proměnnou a ta byla nahrazena její hodnotou, jako by to udělal Sass.
Nápad za postprocesory je ten, že jednou budou prohlížeče podporovat nové funkce (například CSS proměnné), postprocesory je nezkompilují, nechají je být a nechají prohlížeče ať se starají.
Zatímco poskytování zítřejší syntaxe už dnes je opravdu ušlechtilý nápad, musím říci, že pořád preferuji používání Sassu pro většinu věcí. Každopádně jsou tu některé případy, kde věřím, že je použití postprocesorů více vhodné, než-li Sass a tak podobně, například CSS prefixování, ale k tomu se vrátíme.
Další četba:
Úvod
Proč mít příručku
Příručka není jenom bezvýznamný dokument na bezduché přečtení, nebo představení ideálního stavu pro váš kód. Je to klíčový dokument projektu, který popisuje, jak a proč psát kód. Pro malé projekty se může zdát spíše jako zbytečnost, ale opravdu dost pomáhá udržovat codebase čistou a jednoduše upravitelnou.
Netřeba ani říkat, že čím více vývojářů je zapojeno v projektu, tím více je manuál pro psaní kódu dost potřebný. Stejně tak čím větší je projekt, tím více je manuál potřeba.
Důležitost dobře uvádí Harry Roberts v jeho CSS Guidelines:
Příručka pro psaní kódu (poznámka, nikoli ve vizuálním stylu) je hodnotným nástrojem pro týmy, které:
- budou budovat a udržovat produkty přiměřenou dobu;
- mít vývojáře různých schopností a specializací;
- mít několik vývojářů pracujících na produktu v jakýkoli daný čas;
- přijímat pravidelně nové zaměstnance;
- mít několik codebases, do kterých vývojáři mohou zasahovat zřídkakdy.
Podmínky odpovědnosti
Zaprvé: toto není CSS příručka. Tento dokument nebude probírat jmenné konvence pro CSS třídy, modulárních vzorů a otázku problematiky ID v CSS. Tato příručka se zabývá pouze otázkami spojenými se Sass.
Tato příručka je také mojí vlastní a proto je velmi tvrdohlavá. Berte to jako sbírku metodik a rad, které jsem vykoumal v průběhu let. Díky tomu vás mohu také nasměřovat na užitečnou hrstku zdrojů, takže se určitě dívejte na další četbu.
Samozřejmě to není jediná možnost jak dělat věci a hodně může záležet na vašem projektu. Klidně si vyberte a upravte si vše podle vašich potřeb. Jak říkám, záleží na vkusu.
Klíčové principy
Na závěr toho všeho, pokud tu je jediná věc, kterou bych vám rád předal z celé této příručky, je to právě to, že Sass by měl zůstat jednoduchý jak jen to je možné.
Díky mým pošetilým experimentům jako bitový operátor, iterátory a generátory a JSON parser v Sasu, jsme si všichni vědomi, co se dá s takovýmto preprocesorem dělat.
Zatímco je CSS jednoduchý jazyk, Sass, kterým se má psát CSS, by neměl být o nic moc složitější než obyčejné CSS.Hlavní roli zde hraje princip KISS (Keep It Simple Stupid), který může mít v některých případech dokonce přednost před principem DRY (Don’t Repeat Yourself).
Někdy se je lepší trochu opakovat tak, aby se kód dobře upravoval, spíše než vybudovat těžký, nemotorný a zbytečně složitý systém, který se nebude dát udržovat, kvůli jeho komplexnosti.
Stejně tak, a znovu budu citovat Harryho Robertse, pragmatismus přebíjí dokonalost. V nějakém momentu se pravděpodobně nachytáte, když budete dělat něco, co se příčí pravidlům. Pokud to dává smysl a pokud to zní dobře, dělejte to. Kodex je jen prostředkem, nikoli cílem.
Další četba:
Syntaxe & formátování
Pokud byste se mě zeptali, co je první věc, kterou by každá příručka měla obsahovat, bylo by to jak má kód vypadat.
Když se několik vývojářů zapojí do psaní CSS ve stejném projektu, je jen otázkou času, než si jeden z nich začne dělat věci po svém. Manuály pro kód, které podporují konzistenci nejen že tomuto zabraňují, ale také pomáhají pokud jde o čtení a aktualizaci kódu.
Tady je zhruba to, co chceme (beze studu inspirováno CSS Guidelines):
- dvě (2) mezery odsazení, žádné tabulátory;
- ideálně, 80 znaků na řádek;
- správně psané víceřádkové CSS pravidla;
- smysluplné použití mezer.
// Yep
.foo {
display: block;
overflow: hidden;
padding: 0 1em;
}
// Nope
.foo {
display: block; overflow: hidden;
padding: 0 1em;
}
// Since Sass indented-syntax forces those coding standards
// There is no wrong way of proceeding
.foo
display: block
overflow: hidden
padding: 0 1em
V této části nebudeme řešit organizaci souboru. Je to předmětem jiné sekce.
Textové řetězce
Věřte nebo ne, řetězce hrají docela důležitou roli jak v CSS, tak i Sass ekosystémech. Většina CSS hodnod jsou buď délky nebo řetězce (většinou bez uvozovek), takže je docela zásadní držet se nějakého manuálu, pro vypořádávání se s řetězci v Sass.
Kódování
Aby se zabránilo možným problémům s kódováním znaků, je vysoce doporučeno nastavit kódování UTF-8 v hlavním souboru se styly použitím @charset
direktivy. Ujistěte se, že je kódování nastaveno hned na prvním místě ve stylech a není před ním žádný znak.
@charset 'utf-8';
@charset 'utf-8'
Uvozovky
CSS nevyžaduje, aby byly řetězce obaleny uvozovkami, a to ani pokud obsahují mezery. Vezměte si například font-family názvy: CSS parseru nezáleží, jestli je zabalíte do uvozovek.
A právě proto ani Sass nevyžaduje, aby byly řetězce zabaleny uvozovkami. A ještě lépe (a naštěstí, což určitě poznáte), řetězec s uvozovkami je striktně rovnocený k dvojčeti bez uvozovek (tedy například 'abc'
je striktně rovnocenný s abc
).
Jak již bylo řečeno, jazyky, které nevyžadují, aby byly řetězce obaleny uvozovkami jsou jasnou menšinou a proto by měly být řetězce v Sassu vždy zabaleny v jednoduchých uvozovkách ('
) (jednoduché uvozovky bývají snadnější na napsaní než-li dvojité na qwerty klávesnicích). Kromě souladu s ostatními jazyky, včetně CSS bratrance JavaScriptu, je několik důvodů pro tuto volbu:
- jména barev jsou považovány za barvy, pokud jsou bez uvozovek, což může vést k vážným problémům;
- většina zvýrazňovačů syntaxe bude řetězce bez uvozovek považovat za chybu;
- napomáhá obecné čitelnosti;
- není žádný důvod proč řetězce neobalovat uvozovkami.
// Yep
$direction: 'left';
// Nope
$direction: left;
// Yep
$direction: 'left'
// Nope
$direction: left
Textové řetězce jako CSS hodnoty
Specifické CSS hodnoty jako initial
nebo sans-serif
vyžadují, aby nebyly v uvozovkách. Deklarace jako font-family: 'sans-serif'
tiše selže, protože CSS očekává identifikátor, ne řetězec s uvozovkami. Z toho důvodu nepoužíváme uvozovky na tyto hodnoty.
// Yep
$font-type: sans-serif;
// Nope
$font-type: 'sans-serif';
// Okay I guess
$font-type: unquote('sans-serif');
// Yep
$font-type: sans-serif
// Nope
$font-type: 'sans-serif'
// Okay I guess
$font-type: unquote('sans-serif')
Proto můžeme rozlišovat mezi řetězci, které mají být použiti jako CSS hodnoty (CSS identifikátory) jako v předchozím případě a řetězci, které se drží Sass datového typu, jako například klíče mapy.
Nepoužíváme uvozovky v prvním případně, ale v druhém případě využíváme jednoduchých uvozovek.
Textové řetězce obsahující uvozovky
Pokud řetězec obsahuje jednu nebo více jednoduchých uvozovek, může se řetězec namísto toho zabalit dvojitými uvozovkami ("
), aby se zabránilo úniku znaků z řetězce.
// Okay
@warn 'You can\'t do that.';
// Okay
@warn "You can't do that.";
// Okay
@warn 'You can\'t do that.'
// Okay
@warn "You can't do that."
URL
URL by měly být také zabaleny v uvozovkách ze stejných důvodů jako je výše:
// Yep
.foo {
background-image: url('/images/kittens.jpg');
}
// Nope
.foo {
background-image: url(/images/kittens.jpg);
}
// Yep
.foo
background-image: url('/images/kittens.jpg')
// Nope
.foo
background-image: url(/images/kittens.jpg)
Další četba:
Čísla
V Sassu je číslo datový typ, včetně všeho od bezjednotkových čísel po délky, trvání, frekvence, úhly a tak dále. To umožňuje spustit výpočty na těchto opatřeních.
Nuly
Čísla by měla zobrazovat nulu před tečkou pro hodnoty menší než jedna. Nikdy nezobrazujte koncové nuly.
// Yep
.foo {
padding: 2em;
opacity: 0.5;
}
// Nope
.foo {
padding: 2.0em;
opacity: .5;
}
// Yep
.foo
padding: 2em
opacity: 0.5
// Nope
.foo
padding: 2.0em
opacity: .5
Jednotky
Pokud se zaměříme na jednotky, 0
by nikdy neměla mít definovanou jednotku.
// Yep
$length: 0;
// Nope
$length: 0em;
// Yep
$length: 0
// Nope
$length: 0em
Nejčastější chybou, která mě napadne v souvislosti s čísly v Sassu, je ta, že jednotky jsou jen nějaké textové řetězce, které mohou být bezpečně dosazeny k číslu. I když to je pravda, určitě to není jak jednotky fungují. Představte si jednotky jako algebraické symboly. Například v reálném světě, násobení 5 centimetrů 5 centimetry vám dá 25 centimetrů čtverečních. Stejná logika platí i pro Sass.
Pro přidání jednotky k číslu musíte číslo vynásobit 1 jednotkou.
$value: 42;
// Yep
$length: $value * 1px;
// Nope
$length: $value + px;
$value: 42
// Yep
$length: $value * 1px
// Nope
$length: $value + px
Všimněte si, že 0 členů té jednotky také funguje, ale já bych vám raději doporučoval zmíněnou metodu, jelikož přidáním 0 jednotky může být tak trochu matoucí. Avšak pokud se budete snažit převést číslo do jiné kompatibilní jednotky, přidání 0 na to nebude stačit.
$value: 42 + 0px;
// -> 42px
$value: 1in + 0px;
// -> 1in
$value: 0px + 1in;
// -> 96px
$value: 42 + 0px
// -> 42px
$value: 1in + 0px
// -> 1in
$value: 0px + 1in
// -> 96px
Nakonec to všechny závisí na tom, čeho se snažíte dosáhnout. Jenom mějte na paměti, že přidáním jednotky v řetězci není dobrou cestou jak to dělat.
Pro odstranění jednotky z hodnoty ji musíte vydělit jednou jednotkou svého druhu.
$length: 42px;
// Yep
$value: $length / 1px;
// Nope
$value: str-slice($length + unquote(''), 1, 2);
$length: 42px
// Yep
$value: $length / 1px
// Nope
$value: str-slice($length + unquote(''), 1, 2)
Připojením jednotky v řetězci k číslu vznikne řetězec, který zamezí jakýmkoli dalším operacím na hodnotě. Krajení numerické části čísla jednotkou také vyústí v řetězec. A to není to, co chcete.
Výpočty
Numerické výpočty na nejvyšší úrovni by měly být vždy zabaleny v závorkách. Nejen, že tento požadavek výrazně zlěpší čitelnost, ale také zabrání některým krajním případům tím, že nutí Sass vyhodnotit obsah závorek.
// Yep
.foo {
width: (100% / 3);
}
// Nope
.foo {
width: 100% / 3;
}
// Yep
.foo
width: (100% / 3)
// Nope
.foo
width: 100% / 3
Magická čísla
“Magická čísla” je old school programovací termín pro nepojmenované matematické konstanty. V podstatě to je jen náhodné číslo, které prostě funguje™ a zatím není vázáno na žádné logické vysvětlení.
Netřeba snad ani dodávat, že magická čísla jsou mor a mělo by se jim vyhýbat za jakoukoli cenu. Pokud nemůžete najít rozumné vysvětlení, proč číslo funguje, přidejte rozsáhlý komentář vysvětlující jak jste se tam dostali a proč si myslíte, že to funguje. Přiznáním se, že nevíte proč něco funguje je stále více užitečné pro dalšího vývojáře, než aby sám musel přijít na to co se děje on nuly.
/**
* 1. Magic number. This value is the lowest I could find to align the top of
* `.foo` with its parent. Ideally, we should fix it properly.
*/
.foo {
top: 0.327em; /* 1 */
}
/**
* 1. Magic number. This value is the lowest I could find to align the top of
* `.foo` with its parent. Ideally, we should fix it properly.
*/
.foo
top: 0.327em /* 1 */
Další četba:
Barvy
Barvy zaujímají v CSS jazyce důležité místo. Jako obvykle, Sass je nakonec cenným spojencem když přijde na řadu manipulace s barvami, především proto, jelikož obsahuje mocné funkce.
Formáty barev
Aby byly barvy tak jednoduché, jak jen mohou být, moje rada je respektovat následující pořadí formátů barev:
- CSS klíčová slova pro barvy;
- HSL notace;
- RGB notace;
- Hexadecimální notace. Přednostně malá písmena a zkrácené kde je jen možné.
Pro začátek, klíčová slova často mluví sami za sebe. HSL reprezentace je nejen ta nejjednodušší pro lidský mozek na pochopení [citation needed], ale také ulehčuje autorům stylu vyladit barvu úpravou odstínu, sytosti a světlosti individuálně. RGB má stále tu výhodu, že hned vidíte, jestli má barva více modré, zelené, nebo červené, ale to neznamená, že je vytvoření barvy ze tří částí jednoduché. Poslední, hexadecimální, je pro lidskou mysl skoro nečitelný.
// Yep
.foo {
color: hsl(0, 100%, 50%);
}
// Also yep
.foo {
color: rgb(255, 0, 0);
}
// Meh
.foo {
color: #f00;
}
// Nope
.foo {
color: #FF0000;
}
// Nope
.foo {
color: red;
}
.foo
color: hsl(0, 100%, 50%)
// Also yep
.foo
color: rgb(255, 0, 0)
// Nope
.foo
color: #f00
// Nope
.foo
color: #FF0000
// Nope
.foo
color: red
Při používání HSL nebo RGB notace vždy přidejte jednu mezeru po čárce (,
), ale nepřidávejte žádnou mezeru mezi závorkami ((
, )
) a obsahem.
// Yep
.foo {
color: rgba(0, 0, 0, 0.1);
background: hsl(300, 100%, 100%);
}
// Nope
.foo {
color: rgba(0,0,0,0.1);
background: hsl( 300, 100%, 100% );
}
// Yep
.foo
color: rgba(0, 0, 0, 0.1)
background: hsl(300, 100%, 100%)
// Nope
.foo
color: rgba(0,0,0,0.1)
background: hsl( 300, 100%, 100% )
Barvy a proměnné
Pokud barvu používáte více než jednou, uložte jí do proměnné se smysluplným názvem reprezentující barvu.
$sass-pink: hsl(330, 50%, 60%);
$sass-pink: hsl(330, 50%, 60%)
Odteď budete moci používat tuto proměnnou kdekoliv chcete. Pokud je však vaše proměnná velmi svázaná s tématem, radil bych, abyste ji nepoužívali tak, jak je. Namísto toho ji uložte v jiné proměnné se jménem vysvětlující, jak by se měla používat.
$main-theme-color: $sass-pink;
$main-theme-color: $sass-pink
Tímto zabráníte problémům vyplývajících ze změny tématu jako $sass-pink: blue
.
Zesvětlení a ztmavení barev
Obě, lighten
a darken
funkce manipulují ze světlostí barvy v HSL formátu přidáním nebo odebráním světlosti. V podstatě nejsou ničím jiným než jen alias pro $lightness
parametr adjust-color
funkce.
Věc se má tak, že tyto funkce často neprovádí očekávaný výsledek. Na druhou stranu mix
funkce je pěkná cesta, jak zesvětlit nebo ztmavit barvu namícháním s white
nebo black
.
Výhoda ve využívání mix
spíše než jednu z těch dvou funkcí shora je, že postupně půjde do černé (nebo bílé), jak budete snižovat poměr barvy, zatímco darken
a lighten
rychle sfouknou barvu do černé nebo bílé.
Pokud nechcete pokaždé psát mix
funkci, můžete vytvořit dvě jednoduché funkce tint
a shade
(které jsou také částí Compass) aby dělaly tu stejnou věc:
/// Slightly lighten a color
/// @access public
/// @param {Color} $color - color to tint
/// @param {Number} $percentage - percentage of `$color` in returned color
/// @return {Color}
@function tint($color, $percentage) {
@return mix(white, $color, $percentage);
}
/// Slightly darken a color
/// @access public
/// @param {Color} $color - color to shade
/// @param {Number} $percentage - percentage of `$color` in returned color
/// @return {Color}
@function shade($color, $percentage) {
@return mix(black, $color, $percentage);
}
/// Slightly lighten a color
/// @access public
/// @param {Color} $color - color to tint
/// @param {Number} $percentage - percentage of `$color` in returned color
/// @return {Color}
@function tint($color, $percentage)
@return mix($color, white, $percentage)
/// Slightly darken a color
/// @access public
/// @param {Color} $color - color to shade
/// @param {Number} $percentage - percentage of `$color` in returned color
/// @return {Color}
@function shade($color, $percentage)
@return mix($color, black, $percentage)
Funkce scale-color
je navržena tak, že škáluje vlastnosti více plynule tím, že vezme v úvahu, jak vysoké nebo nízké již jsou. To by mělo poskytnou výsledky, které jsou hezké jako mix
, ale s jasnější konvencí pro volání. Měřítko přesně totéž.
Další četba:
- A Visual Guide to Sass & Compass Color Functions
- How to Programmatically Go From One Color to Another
- Sass Color Variables That Don’t Suck
- Using Sass to Build Color Palettes
- Dealing with Color Schemes in Sass
Seznamy
Seznamy jsou Sass verzí polí. Seznam má strukturu jednorozměrného pole (na rozdíl od mapy), které jsou navrženy tak, aby mohly obsahovat hodnoty jakéhokoli typu (včetně listů, což vede k vnořeným seznamům).
Seznamy by měly být tvořeny podle následujícího manuálu:
- buď je jednořádkový nebo víceřádkový;
- pokud je příliš dlouhý, aby se vešel na 80 znaků, musí být víceřádkový;
- pokud není používaný pro účely CSS, vždy se položky rozdělují čárkami;
- vždy musí být zabalený v závorkách;
- koncová čárka se přidává pokud je víceřádkový, pokud je jednořádkový, tak ne.
// Yep
$font-stack: ('Helvetica', 'Arial', sans-serif);
// Yep
$font-stack: (
'Helvetica',
'Arial',
sans-serif,
);
// Nope
$font-stack: 'Helvetica' 'Arial' sans-serif;
// Nope
$font-stack: 'Helvetica', 'Arial', sans-serif;
// Nope
$font-stack: ('Helvetica', 'Arial', sans-serif,);
// Yep
$font-stack: ('Helvetica', 'Arial', sans-serif)
// Nope (not supported)
$font-stack: (
'Helvetica',
'Arial',
sans-serif,
)
// Nope
$font-stack: 'Helvetica' 'Arial' sans-serif
// Nope
$font-stack: 'Helvetica', 'Arial', sans-serif
// Nope
$font-stack: ('Helvetica', 'Arial', sans-serif,)
Pokud přidáváte nové položky do seznamu, vždy používejte dodávané API. Nepokoušejte se přidávat položky manuálně.
$shadows: (0 42px 13.37px hotpink);
// Yep
$shadows: append($shadows, $shadow, comma);
// Nope
$shadows: $shadows, $shadow;
$shadows: (0 42px 13.37px hotpink)
// Yep
$shadows: append($shadows, $shadow, comma)
// Nope
$shadows: $shadows, $shadow
Další četba:
Mapy
Již od Sassu 3.3 mohou autoři definovat mapy — což je Sass termín pro asociativní pole, hashe, nebo dokonce JavaScript objekty. Mapa je datová struktura, která mapuje klíče (což mohou být jakékoli datové typy, včetně map, což bych ale nedoporučoval) k hodnotám jakéhokoli datového typu.
Mapy by se měly psát tak, jako je popsáno níže:
- mezera za dvojtečkou (
:
); - otevírací závorka (
(
) na stejném řádku jako dvojtečka (:
); - pokud je klíč textový řetězec, pak by měl být v uvozovkách (což je 99% případů);
- každý pár klíč/hodnota na svém vlastním řádku;
- čárka (
,
) na konci každého páru klíč/hodnota; - koncová čárka (
,
) by měla být i na konci poslední položky, pro snadnější přidávání, odstraňování, nebo změnu pořadí položek; - uzavírací závorka (
)
) na novém řádku; - žádná mezera nebo nový řádek mezi uzavírací závorkou (
)
) a středníkem (;
).
Ilustrace:
// Yep
$breakpoints: (
'small': 767px,
'medium': 992px,
'large': 1200px,
);
// Nope
$breakpoints: ( small: 767px, medium: 992px, large: 1200px );
// Yep
$breakpoints: ('small': 767px, 'medium': 992px, 'large': 1200px,)
// Nope
$breakpoints: ( 'small': 767px, 'medium': 992px, 'large': 1200px )
// Nope
$breakpoints: (small: 767px, medium: 992px, large: 1200px,)
// Nope (since it is not supported)
$breakpoints: (
'small': 767px,
'medium': 992px,
'large': 1200px,
)
Debugování Sass map
Pokud se někdy ocitnete ztraceni, nebo budete přemýšlet, co za šílenou magii se právě v Sass mapě děje, pak se nebojte, protože je tu stále možnost záchrany.
@mixin debug-map($map) {
@at-root {
@debug-map {
__toString__: inspect($map);
__length__: length($map);
__depth__: if(function-exists('map-depth'), map-depth($map), null);
__keys__: map-keys($map);
__properties__ {
@each $key, $value in $map {
#{'(' + type-of($value) + ') ' + $key}: inspect($value);
}
}
}
}
}
=debug-map($map)
@at-root
@debug-map
__toString__: inspect($map)
__length__: length($map)
__depth__: if(function-exists('map-depth'), map-depth($map), null)
__keys__: map-keys($map)
__properties__
@each $key, $value in $map
#{'(' + type-of($value) + ') ' + $key}: inspect($value)
Pokud jste zvědavi, do jaké hloubky vaše mapa sahá, přidejte následující funkci. Mixin ji zobrazí automaticky.
/// Compute the maximum depth of a map
/// @param {Map} $map
/// @return {Number} max depth of `$map`
@function map-depth($map) {
$level: 1;
@each $key, $value in $map {
@if type-of($value) == 'map' {
$level: max(map-depth($value) + 1, $level);
}
}
@return $level;
}
/// Compute the maximum depth of a map
/// @param {Map} $map
/// @return {Number} max depth of `$map`
@function map-depth($map)
$level: 1
@each $key, $value in $map
@if type-of($value) == 'map'
$level: max(map-depth($value) + 1, $level)
@return $level;
Další četba:
- Using Sass Maps
- Debugging Sass Maps
- Extra Map functions in Sass
- Real Sass, Real Maps
- Sass Maps are Awesome
- Sass list-maps
- Sass Maps Plus
- Sassy-Maps
- Introduction to Sass Maps Usage and Examples
CSS pravidla
V tuto chvíli zde uvedu, co většina asi ví, jak by měly být CSS pravidla psány (nebo alespoň jak je nejvíce uvedeno v manuálech, včetně CSS Guidelines):
- související selektory na stejném řádku; nesouvisející na nových řádcích;
- otevírací závorka (
{
) oddělena jednou mezerou od posledního selektoru; - každá deklarace na svém vlastním řádku;
- mezera za středníkem (
:
); - uzavírací středník (
;
) na konci každé deklarace; - uzavírací závorka (
}
) na svém vlastním novém řádku; - nový řádek po uzavírací závorce
}
.
Ilustrace:
// Yep
.foo, .foo-bar,
.baz {
display: block;
overflow: hidden;
margin: 0 auto;
}
// Nope
.foo,
.foo-bar, .baz {
display: block;
overflow: hidden;
margin: 0 auto }
// Yep
.foo, .foo-bar,
.baz
display: block
overflow: hidden
margin: 0 auto
// Nope
.foo,
.foo-bar, .baz
display: block
overflow: hidden
margin: 0 auto
Přidáním těchto pokynů k CSS budeme dávat pozor na toto:
- deklarovat lokální proměnné před jakoukoli deklarací, potom oddělit of deklarace novým řádkem;
- volání mixinů bez
@content
před jakoukoli deklarací; - vnořené selektory vždy po novém řádku;
- volání mixinů s
@content
po vnořených selektorech; - žádný řádek před zavírací závorkou (
}
).
Ilustrace:
.foo, .foo-bar,
.baz {
$length: 42em;
@include ellipsis;
@include size($length);
display: block;
overflow: hidden;
margin: 0 auto;
&:hover {
color: red;
}
@include respond-to('small') {
overflow: visible;
}
}
.foo, .foo-bar,
.baz
$length: 42em
+ellipsis
+size($length)
display: block
overflow: hidden
margin: 0 auto
&:hover
color: red
+respond-to('small')
overflow: visible
Další četba:
Řazení deklarace
Nenapadá mě snad žádné jiné téma, kde jsou názory tak rozdělené jako právě v řazení CSS deklarací. Konkrétně se dělí na dvě frakce:
- držet se abecedního pořadí;
- řadit deklarace dle typu (pozice, zobrazení, barvy, písmo, a další…).
V obou případech najdete výhody i nevýhody. Na jednu stranu je abecení pořadí univerzální (alespoň pro jazyky, které používají latinku), takže nemůže nastat situace, kdy se budete muset rozhodnout, jestli toto bude před tím, nebo ne. Každopádně vidět bottom
a top
od sebe je tak trochu divné. Proč by měly animace být před typem zobrazení? S abecedním pořadí existuje dost zvláštností.
.foo {
background: black;
bottom: 0;
color: white;
font-weight: bold;
font-size: 1.5em;
height: 100px;
overflow: hidden;
position: absolute;
right: 0;
width: 100px;
}
.foo
background: black
bottom: 0
color: white
font-weight: bold
font-size: 1.5em
height: 100px
overflow: hidden
position: absolute
right: 0
width: 100px
Na druhou stranu, řazení vlastností podle typu dává perfektní smysl. Každá deklarace okolo písma je u sebe, top
a bottom
jsou znovu u sebe a číst pravidla je jako číst krátký příběh. Ale dokud nezačnete používat nějaké konvence jako Idiomatic CSS, je tu spoustu možností jak danou věc udělat. Kde by se měla řadit white-space
? Do písma, nebo zobrazení? Kam přesně patří overflow
? Jaké je pořadí vlastností v dané skupině (mělo by to být abecedně, jaká to ironie)?
.foo {
height: 100px;
width: 100px;
overflow: hidden;
position: absolute;
bottom: 0;
right: 0;
background: black;
color: white;
font-weight: bold;
font-size: 1.5em;
}
.foo
height: 100px
width: 100px
overflow: hidden
position: absolute
bottom: 0
right: 0
background: black
color: white
font-weight: bold
font-size: 1.5em
Je tu také další zajímavý způsob řazení nazývaný Concentric CSS, což vypadá, že je také populární. Concentric CSS pro určení pořadí v podstatě spoléhá na box-model.
.foo {
width: 100px;
height: 100px;
position: absolute;
right: 0;
bottom: 0;
background: black;
overflow: hidden;
color: white;
font-weight: bold;
font-size: 1.5em;
}
.foo
width: 100px
height: 100px
position: absolute
right: 0
bottom: 0
background: black
overflow: hidden
color: white
font-weight: bold
font-size: 1.5em
Musím říci, že se sám nemohu rozhodnout. Nedávný průzkum na CSS-Tricks zjistil, že přes 45% vývojářů řadí své deklarace podle typu a oproti tomu 14% abecedně. Ale je tu také 39%, kteří vše řadí náhodně, včetně mě.
Právě proto nebudu do příručky dávat doporučení na výběr. Vyberte si tu, kterou preferujete vy, jen buďte ve všech stylech konzistentní (tedy žádná náhodná možnost).
Nedávná studie ukazuje, že používání CSS Comb (což používá řazení podle typu) pro řazení CSS deklarací končí s zkrácením průměrné velikosti pod Gzip kompresí o 2,7%, v porovnání 1,3% když je řazení podle abecedy.
Další četba:
- CSS Comb
- Concentric CSS
- Idiomatic CSS
- On Declaration Sorting
- Reduce File Size With CSS Sorting
- Poll Results: How Do You Order Your CSS Properties?
Noření selektorů
Jedna konkrétní funkce Sass, která je až příliš zneužívána spoustou vývojářů je noření selektorů. Noření selektorů nabízí způsob, jak se autoři stylů mohou vypořádat s dlouhými selektory vnořováním menších v dalších.
Obecné pravidlo
Například následující vnořování v Sass:
.foo {
.bar {
&:hover {
color: red;
}
}
}
.foo
.bar
&:hover
color: red
… vygeneruje toto CSS:
.foo .bar:hover {
color: red;
}
Ve stejném duchu, od Sass 3.3, je možné použít referenci na aktuální selektor (&
) ke generování rozšířených selektorů. Například:
.foo {
&-bar {
color: red;
}
}
.foo
&-bar
color: red
… vygeneruje toto CSS:
.foo-bar {
color: red;
}
.foo-bar
color: red
Tento způsob se často používá spolu s BEM jmennou konvencí pro generování .block__element
a .block--modifier
selektorů založených na originálním selektoru (tedy v tomto případě .block
).
Ačkoliv je to možná neoficiální, generování nových selektorů z reference aktuálního selektoru (&
) dělá tyto selektory nedosažitelné v codebase, protože samy o sobě neexistují.
Problém s vnořenými selektory je ten, že je v konečném důsledku dělá hůře čitelné. Každý si pak musí v hlavně domyslet výsledný selektor z úrovně odsazení, což není vždy až tak jasné, jak se může zdát.
Toto tvrzení se stává skutečnější čím dál tím více, čím je aktuální selektor (&
) četnější. Od nějakého bodu je také čím dál tím větší riziko, že nikdo nepochopí, co se děje, že to za to ani nestojí.
Abyste se takovýmto situacím vyhnuli, vyhýbejte se vnořeným selektorům jak jen to jde. Každopádně pro toto pravidlo je samozřejmě pár výjimek.
Výjimky
Pro začátek, je dovoleno a dokonce doporučeno nořit pseudo třídy a pseudo elementy do původního selektoru.
.foo {
color: red;
&:hover {
color: green;
}
&::before {
content: 'pseudo-element';
}
}
.foo
color: red
&:hover
color: green
&::before
content: 'pseudo-element'
Používání noření pro pseudo třídy a pseudo selektory nejenom že dává smysl (protože se vypořádává s úzce souvisejícími selektory), ale také pomáhá udržet všechno o komponentě na jednom místě.
Také když používáte třídy, které určují pravdivost, jako například .is-active
, je naprosto v pořádku vnořit ji do selektoru komponenty, abyste zachovali věci v pořádku.
.foo {
// …
&.is-active {
font-weight: bold;
}
}
.foo
// …
&.is-active
font-weight: bold
V neposlední řadě, když stylujete element protože musí být obsažen v nějakém specifickém elementu, je často fajn použít noření k udržení všeho o komponentě na stejném místě.
.foo {
// …
.no-opacity & {
display: none;
}
}
.foo
// …
.no-opacity &
display: none
Když pracujete s nezkušenými vývojáři, selektor jako .no-opacity &
může vypadat tak trochu divně. Abyste zabránili jakýmkoli rozpakům, můžete udělat velmi krátký mixin, který přemění tuto divnou syntaxi na výslovné API.
/// Helper mixin to provide simple API to selector nesting
/// @param {String} $selector - Selector
@mixin when-inside($selector) {
#{$selector} & {
@content;
}
}
/// Helper mixin to provide simple API to selector nesting
/// @param {String} $selector - Selector
=when-inside($selector) {
#{$selector} &
@content
}
Přepsáním předešlého příkladu by to vypadalo asi takto:
.foo {
// …
@include when-inside('.no-opacity') {
display: none;
}
}
.foo
// …
+when-inside('.no-opacity')
display: none
Jako asi se vším, specifika jsou poněkud nedůležitá, důležitá je konzistence. Pokud noření plně důvěřujete, klidně noření používejte. Jenom se ujistěte, že to nikomu z vašeho týmu nevadí.
Další četba:
Pokud se vám Sass Guidelines líbí, zvažte, prosím, jeho podporu.
Podpořit Sass GuidelinesJmenné konvence
V této sekci se nebudeme zabývat nejlepšími jmennými CSS konvencemi pro udržovatelnost a rozsah. Nejen že je to jen a jen na vás, ale je to také mimo oblast Sass manuálu. Navrhuji však ty, které jsou doporučeny v CSS Guidelines.
Je tu však pár věcí, které můžete v Sassu pojmenovat a je důležité je pojmenovat dobře, takže celý codebase bude vypadat konzistentní a bude snadno čitelný:
- proměnné;
- funkce;
- mixiny.
Sass placeholdery jsou z tohoto seznamu úmyslně vynechány, jelikož mohou být považovány za běžné CSS selektory a proto na ně platí stejné vzory pro název jako pro třídy.
Pokud jde o proměnné, funce a mixiny, držme se něčeho velmi ve stylu CSS: malé písmo oddělené pomlčkami a především smysluplného.
$vertical-rhythm-baseline: 1.5rem;
@mixin size($width, $height: $width) {
// …
}
@function opposite-direction($direction) {
// …
}
$vertical-rhythm-baseline: 1.5rem
=size($width, $height: $width)
// …
@function opposite-direction($direction)
// …
Další četba:
Konstanty
Pokud jste náhodou vývojáři frameworku, nebo píšete knihovnu, pravděpodobně se potýkáte s proměnnými, které nejsou zamýšleny tak, aby se daly upravovat: konstanty. Bohužel (nebo naštěstí?) Sass neumožňuje žádnou cestu pro takovouto věc, takže si musíme vystačit s jmennými konvencemi.
Tak jako pro mnoho jazyků, doporučuji proměnné, pokud jsou konstantami, psát velkým písmem. Nejen že je to velmi stará konvence, ale také snadno poznáte, že je daná proměnná právě konstantou, jelikož je v kontrastu s proměnnými psanými malým písmem a oddělenými pomlčkami.
// Yep
$CSS_POSITIONS: (top, right, bottom, left, center);
// Nope
$css-positions: (top, right, bottom, left, center);
// Yep
$CSS_POSITIONS: (top, right, bottom, left, center)
// Nope
$css-positions: (top, right, bottom, left, center)
Další četba:
Namespace
Pokud máte v úmyslu svůj Sass kód rozšířit, v případě knihovny, frameworku, grid systému nebo čehokoli, pravděpodobně zvažujete použít namespace na všechny vaše proměnné, funkce, mixiny a placeholdery, takže nebude moci dojít ke konfliktu s kódem někoho jiného.
Například, pokud pracujete na projektu Sassy Unicorn, se kterým budou moci pracovat vývojáři z celého světa (kdo by ne, že ano?), můžete zvážit použít su-
jako namespace. Je to dost specifické aby se zabránilo jakémukoli kolidování názvu a krátké dost na to, aby to nebolelo psát.
$su-configuration: ( … );
@function su-rainbow($unicorn) {
// …
}
$su-configuration: ( … )
@function su-rainbow($unicorn)
// …
Poznámka: automatické namespacy budou definitivně designový cíl pro připravovaný @import
od Sassu 4.0. Čím je blíže k uskutečnění, tím je méně a méně užitečné dělat namespace ručně. Případně ručně namespacované knihovny mohou být složitější na použití.
Další četba:
Architektura
Navrhnout architekturu CSS projektu je pravděpodobně jedna z nejvíce těžkých věcí, kterou budete muset v životě projektu udělat. Udržovat návrh konzistentní a smysluplný je ještě těžší.
Naštěstí, jedna z hlavních výhod používání CSS preprocesoru je schopnost rozdělit codebase do několika souborů bez dopadu na výkon (jako dělá CSS direktiva @import
). Díky přetížení Sass @import
direktiv je naprosto bezpečné (a vlastně i doporučované) používat tak mnoho souborů, kolik je ve vývoji nezbytné a všechno pro produkci kompilovat do jednoho stylu.
Nad vším tímhle snad ani nemohu dostatečně zdůraznit potřebu složek, a to dokonce i u malých projektů. Doma také nedáváte každý list papíru do jedné a té samé krabice. Používáte složky. Jednu pro dům/byt, jednu pro banku, jednu pro účty, a tak dále. Není tedy žádný důvod dělat to jinak při strukturování CSS projektu. Rozdělte codebase do smysluplně rozdělených složek tak, ať je později jednoduché najít věci, když se do kódu vrátíte později.
Je tu hodně populárních architektur pro CSS projekty: OOCSS, Atomic Design, Bootstrap-like, Foundation-like… Všechny mají své přednosti, klady a zápory.
Já sám používám přístup shodou okolností docela podobný k SMACSS od Jonathan Snook, který se zaměřuje na udržování věcí jednoduchých a jasných.
Naučil jsem se, že architektura je většinou velmi specifická pro daný projekt. Neváhejte jí tedy kompletně zrušit, nebo upravit navrhované řešení tak, aby jste se vypořádali se systémem, který sedí vašim potřebám.
Další četba:
- Architecture for a Sass project
- A Look at Different Sass Architectures
- SMACSS
- An Introduction to OOCSS
- Atomic Web Design
- Sass, une architecture composée
Komponenty
Je tu podstatný rozdíl mezi děláním to funkční a děláním to dobře. Znovu, CSS je tak trochu nepořádný jazyk [nutná citace]. Čím méně CSS máme, tím lépe. Nechceme se zabývat s megybyty CSS kódu. Chcete-li zachovat styly krátké a efektivní—a to pro vás nebude žádné překvápko—je většinou dobrý nápad přemýšlet o rozhraní jako o kolekci komponent.
Komponenty mohou být cokoliv, tak dlouho dokud:
- dělají pouze jednu věc;
- jsou v projektu znovu použitelné;
- jsou nezávislé.
Například vyhledávací formulář by měl být považován za komponentu. Měl by být znovu použitelný, na různých místech, na různých stránkách, v rozdílných situacích. Neměl by záviset na pozici v DOM (patička, postranní panel, hlavní obsah…).
Většina z jakéhokoliv rozhraní se dá představit jako malé komponenty a hodně doporučuji, abyste se drželi tohoto paradigmatu. Tím se nejen že zkrátí množství potřebného CSS pro celý projekt, ale také to bude jednodušší spravovat spíše než-li chaotický nepořádek, kde je všechno vyvedeno z míry.
Vzor 7-1
Zpátky k architektuře, můžeme? Obvykle pracuji s tím, čemu říkám vzor 7-1: 7 složek, 1 soubor. V podstatě máte všechny své partials nacpané do 7 různých složek a jeden soubor na kořenové úrovni (obvykle pojmenován main.scss
) je všechny importuje do CSS stylu.
base/
components/
layout/
pages/
themes/
utils/
vendors/
A samozřejmě:
main.scss
Ideálně můžeme přijít s něčím jako je toto:
sass/
|
|– abstracts/
| |– _variables.scss # Sass Variables
| |– _functions.scss # Sass Functions
| |– _mixins.scss # Sass Mixins
| |– _placeholders.scss # Sass Placeholders
|
|– base/
| |– _reset.scss # Reset/normalize
| |– _typography.scss # Typography rules
| … # Etc.
|
|– components/
| |– _buttons.scss # Buttons
| |– _carousel.scss # Carousel
| |– _cover.scss # Cover
| |– _dropdown.scss # Dropdown
| … # Etc.
|
|– layout/
| |– _navigation.scss # Navigation
| |– _grid.scss # Grid system
| |– _header.scss # Header
| |– _footer.scss # Footer
| |– _sidebar.scss # Sidebar
| |– _forms.scss # Forms
| … # Etc.
|
|– pages/
| |– _home.scss # Home specific styles
| |– _contact.scss # Contact specific styles
| … # Etc.
|
|– themes/
| |– _theme.scss # Default theme
| |– _admin.scss # Admin theme
| … # Etc.
|
|– vendors/
| |– _bootstrap.scss # Bootstrap
| |– _jquery-ui.scss # jQuery UI
| … # Etc.
|
`– main.scss # Main Sass file
Soubory následují stejné jmenné konvence jako je popsáno výše: jsou oddelene-pomlckou.
Složka base
Složka base/
obsahuje to, co bychom mohli nazvat ‘často používaný kód’ projektu. Můžete tam najít soubor pro resetování, nějaké pravidla pro typografii a pravděpodobně styl (který nazývám _base.scss
), který definuje nějaké standardní styly pro obyčejně používané HTML elementy.
_base.scss
_reset.scss
_typography.scss
Složka layout
Složka layout/
obsahuje vše, co se podílí na rozvržení stránky nebo aplikace. Tato složka může obsahovat styly pro hlavní části stránky (hlavička, patička, navigace, postranní panel…), grid systém nebo dokonce CSS styly pro všechny formuláře.
_grid.scss
_header.scss
_footer.scss
_sidebar.scss
_forms.scss
_navigation.scss
Složka layout/
může být také nazývána partials/
, záleží především na tom, co preferujete.
Složka components
Pro menší komponenty tu je složka components/
. Zatímco layout/
je makro (definuje globální wireframe), components/
je více zaměřený na widgety. Obsahuje všechny druhy specifických modulů jako slider, loader, widget a v podstatě cokoliv v tomto směru. V components/
je obvykle hodně souborů, protože celá stránka/aplikace by měla být převážně složena z malých modulů.
_media.scss
_carousel.scss
_thumbnails.scss
Složka components/
může být také nazývána modules/
, záleží především na tom, co preferujete.
Složka pages
Pokud máte styly specifické pro jednotlivé stránky, je nejlepší je umístit do složky pages/
, do souboru pojmenovaného po stránce. Není neobvyklé mít například velmi specifické styly pro úvodní stránku, proto je pak potřeba soubor _home.scss
ve složce pages/
.
_home.scss
_contact.scss
Tyto soubory mohou být nazvány jako jen chcete, závisí na vašem projektu, ale je nutné, abyste se vyhnuli jejich sloučení s ostatními ve výsledném stylu. Je to vážně jen na vás.
Složka themes
Na velkých stránkách a aplikacích není neobvyklé mít rozdílné témata. Jsou tu jistě různé způsoby, jak se přáve s tématy vyrovnat, ale já osobně je mám rád všechny ve složce themes/
.
_theme.scss
_admin.scss
Toto je velmi specifické pro daný projekt a je proto pravděpodobné, že ji v mnoha projektech mít nebudete.
Složka utils
Složka utils/
shromažďuje všechny Sass nástroje a helpery použité napříč projektem. Měla by tu být každý globální proměnná, funkce, mixin a placeholder.
Pravidlem této složky je to, že by se neměl vypsat ani jeden řádek stylů po kompilaci. Nejedná se o nic jiného než o Sass helpery.
_variables.scss
_mixins.scss
_functions.scss
_placeholders.scss
(často pojmenované jako_helpers.scss
)
Složka utils/
může být také nazývána helpers/
, sass-helpers/
nebo sass-utils/
, záleží co preferujete vy osobně.
Složka vendors
V neposlední řadě mnoho projektů bude mít složku vendors/
obsahující všechny CSS soubory od externích knihoven a frameworků - Normalize, Bootstrap, jQueryUI, FancyCarouselSliderjQueryPowered, a tak dále. Odložení všech těchto věcí stranou do jedné složky je dobrý způsob, jak říci „Hej, tohle není ode mne, není to můj kód, není to má zodpovědnost“.
_normalize.scss
_bootstrap.scss
_jquery-ui.scss
_select2.scss
Pokud musíte přepsat sekci nějakého vendoru, doporučuji mít 8. složku nazvanou vendors-extensions/
, ve které můžete mít soubory pojmenované přesně podle těch vendorů, které přepisují.
Například vendors-extensions/_bootstrap.scss
je soubor obsahující všechny CSS pravidla, které předeklarovávají nějaké Bootstrap defaultní CSS. A to proto, aby se zabránilo editaci vendor souborů samo o sobě, což obecně není dobrý nápad.
Hlavní soubor
Hlavní soubor (obvykle označován main.scss
) by měl být jediný Sass soubor z celého codebase, který nezačíná na podtržítko. Tento soubor by neměl obsahovat nic více než @import
a komentáře.
Soubory by měly být importovány podle složky, ve které se nachází a jeden po druhém v následujícím pořadí:
vendors/
utils/
base/
layout/
components/
pages/
themes/
V zájmu zachování čitelnosti by měl hlavní soubor respektovat tyto pokyny:
- jeden soubor na
@import
; - jeden
@import
na řádek; - žádný nový řádek mezi dvěma importy ze stejné složky;
- nový řádek po posledním importu ze složky;
- vynechat přípony souborů a podtržítko na začátku.
@import 'abstracts/variables';
@import 'abstracts/functions';
@import 'abstracts/mixins';
@import 'abstracts/placeholders';
@import 'vendors/bootstrap';
@import 'vendors/jquery-ui';
@import 'base/reset';
@import 'base/typography';
@import 'layout/navigation';
@import 'layout/grid';
@import 'layout/header';
@import 'layout/footer';
@import 'layout/sidebar';
@import 'layout/forms';
@import 'components/buttons';
@import 'components/carousel';
@import 'components/cover';
@import 'components/dropdown';
@import 'pages/home';
@import 'pages/contact';
@import 'themes/theme';
@import 'themes/admin';
@import vendors/bootstrap
@import vendors/jquery-ui
@import utils/variables
@import utils/functions
@import utils/mixins
@import utils/placeholders
@import base/reset
@import base/typography
@import layout/navigation
@import layout/grid
@import layout/header
@import layout/footer
@import layout/sidebar
@import layout/forms
@import components/buttons
@import components/carousel
@import components/cover
@import components/dropdown
@import pages/home
@import pages/contact
@import themes/theme
@import themes/admin
Je tu ještě další způsob importování partials, který také považuji za validní. Na jednu stranu to dělá soubor více čitelným, ale na stranu druhou dělá úpravy trochu více bolestné. Každopádně, nechám vás rozhodnout se, který způsob je nejlepší - moc na tom nezáleží. Pro tento způsob by měl hlavní soubor dodržovat tyto pokyny:
- jeden
@import
na složku; - konec řádku po
@import
; - každý soubor na svém vlastním řádku;
- nový řádek po posledním importu ze složky;
- vynechat přípony souborů a podtžítko na začátku.
@import
'abstracts/variables',
'abstracts/functions',
'abstracts/mixins',
'abstracts/placeholders';
@import
'vendors/bootstrap',
'vendors/jquery-ui';
@import
'base/reset',
'base/typography';
@import
'layout/navigation',
'layout/grid',
'layout/header',
'layout/footer',
'layout/sidebar',
'layout/forms';
@import
'components/buttons',
'components/carousel',
'components/cover',
'components/dropdown';
@import
'pages/home',
'pages/contact';
@import
'themes/theme',
'themes/admin';
@import
vendors/bootstrap,
vendors/jquery-ui
@import
utils/variables,
utils/functions,
utils/mixins,
utils/placeholders
@import
base/reset,
base/typography
@import
layout/navigation,
layout/grid,
layout/header,
layout/footer,
layout/sidebar,
layout/forms
@import
components/buttons,
components/carousel,
components/cover,
components/dropdown
@import
pages/home,
pages/contact
@import
themes/theme,
themes/admin
Abyste nemuseli importovat každý soubor ručně, můžete využít Ruby Sass rozšíření zvané sass-globbing, díky kterému můžete používat globální vzory v Sass @import
jako např. @import "components/*"
.
Jak bylo řečeno, toto řešení bych nedoporučoval, jelikož importujete soubory podle abecedního pořadí, což obvykle není to co chcete, zvláště pokud se musíte vypořádat s pořadím souborů v závislosti na jazyku.
Ostudný soubor
Zajímavý koncept, který zpopularizoval Harry Roberts, Dave Rupert a Chris Coyier, který se skládá z uvedení všech CSS deklarací, hacků a věcí, na které nejsme pyšní do ostudného souboru. Tento soubor, který je dramaticky pojmenován _shame.scss
, by měl být importován po ostatních souborech na konci stylu.
/**
* Nav specificity fix.
*
* Someone used an ID in the header code (`#header a {}`) which trumps the
* nav selectors (`.site-nav a {}`). Use !important to override it until I
* have time to refactor the header stuff.
*/
.site-nav a {
color: #BADA55 !important;
}
/**
* Nav specificity fix.
*
* Someone used an ID in the header code (`#header a {}`) which trumps the
* nav selectors (`.site-nav a {}`). Use !important to override it until I
* have time to refactor the header stuff.
*/
.site-nav a
color: #BADA55 !important
Další četba:
Responzivní Web Design a breakpointy
Nemyslím si, že je Responzivní Web Design stále nutné představovat, když je to nyní snad všude. Každopádně se můžete ptát proč je sekce o RWD v Sass manuálu? Ve skutečnosti existuje pár věcí, které mohou být udělány tak, aby se s breakpointy pracovalo jednodušeji, takže myslím, že by nebyl špatný nápad je tady uvést.
Naming breakpoints
Myslím si, že mohu bez problému říci, že media queries by neměla být vázána na specifické zařízení. Například pokoušet se mířit přímo na iPady nebo Blackberry telefony je určitě špatný nápad. Media queries by se měla starat o různé velikosti obrazovky, dokud se design nerozboří a nenastoupí další media query.
Ze stejného důvodu by breakpointy neměly být pojmenovány podle zařízení ale podle něčeho obecnějšího. Hlavně proto, že některé telefony jsou nyní větší než tablety, některé tablety větší než malé počítače atd.
// Yep
$breakpoints: (
'medium': (min-width: 800px),
'large': (min-width: 1000px),
'huge': (min-width: 1200px),
);
// Nope
$breakpoints: (
'tablet': (min-width: 800px),
'computer': (min-width: 1000px),
'tv': (min-width: 1200px),
);
// Yep
$breakpoints: ('medium': (min-width: 800px), 'large': (min-width: 1000px), 'huge': (min-width: 1200px))
// Nope
$breakpoints: ('tablet': (min-width: 800px), 'computer': (min-width: 1000px), 'tv': (min-width: 1200px))
V tomto bodě naprosto stačí, pokud použijeme jakoukoli jmennou konvenci, která dává smysl a není spjata s konkrétními zařízeními.
$breakpoints: (
'seed': (min-width: 800px),
'sprout': (min-width: 1000px),
'plant': (min-width: 1200px),
);
$breakpoints: ('seed': (min-width: 800px), 'sprout': (min-width: 1000px), 'plant': (min-width: 1200px))
Předešlý příklad používá vnořené mapy pro definování breakpointů, každopádně opravdu záleží jen na vás, jaký druh správy použijete. Můžete se rozhodnout pro textové řetězce, spíše než-li pro vnitřní mapy, kvůli větší pružnosti (tedy '(min-width: 800px)'
).
Další četba:
Správce breakpointů
Jakmile pojmenujete své breakpointy tak, jak chcete, budete potřebovat najít způsob, jak je používat v media queries. Je mnoho způsobů jak tak učinit, ale musím říci, že nejvíce fandím breakpointové mapě, kterou čtu pomocí getter funkce. Tento způsob je zároveň jednoduchý a efektivní.
/// Responsive breakpoint manager
/// @access public
/// @param {String} $breakpoint - Breakpoint
/// @requires $breakpoints
@mixin respond-to($breakpoint) {
$raw-query: map-get($breakpoints, $breakpoint);
@if $raw-query {
$query: if(
type-of($raw-query) == 'string',
unquote($raw-query),
inspect($raw-query)
);
@media #{$query} {
@content;
}
} @else {
@error 'No value found for `#{$breakpoint}`. '
+ 'Please make sure it is defined in `$breakpoints` map.';
}
}
/// Responsive breakpoint manager
/// @access public
/// @param {String} $breakpoint - Breakpoint
/// @requires $breakpoints
=respond-to($breakpoint)
$raw-query: map-get($breakpoints, $breakpoint)
@if $raw-query
$query: if(type-of($raw-query) == 'string', unquote($raw-query), inspect($raw-query))
@media #{$query}
@content
@else
@error 'No value found for `#{$breakpoint}`. '
+ 'Please make sure it is defined in `$breakpoints` map.'
Je zřejmé, že je to poměrně zjednodušující řešení pro správu breakpointů. Pokud potřebujete něco tolerantnějšího, doporučuji vám, abyste znovu nevynalézali kolo a použili něco co bylo ověřeno jako efektivní, právě jako Sass-MQ, Breakpoint nebo include-media.
Další četba:
Použití Media Queries
Ne tak dávno probíhala poměrně vzrušující debata o tom, kde by se měla media queries psát: patří do selektorů (jak to umožňuje Sass) nebo by se měly psát striktně mimo ně? Musím uznat, že jsem vášnivým zastáncem systému media-queries-v-selektorech a myslím si, že to funguje skvěle s ideou komponent.
.foo {
color: red;
@include respond-to('medium') {
color: blue;
}
}
.foo
color: red
+respond-to('medium')
color: blue
Což vede k následujícímu CSS výstupu:
.foo {
color: red;
}
@media (min-width: 800px) {
.foo {
color: blue;
}
}
Mohli jste slyšet, že tato konvence vede k duplikování media queries v CSS výstupu. A je to rozhodně pravda. I když byl udělán test a finální verdikt je, že na tom nezáleží jakmile Gzip (nebo něco podobného) dokončí svou věc:
… probírali jsme, zda existují problémy s výkonem v porovnání kombinování vs rozházení Media Queries a dospěli jsme k závěru, že v nejhorším případě sice ano, ale v nejlepším případě v podstatě vůbec ne.
— Sam Richards, ohledně Breakpoint
Pokud máte obavu ohledně duplicitních media queries, pořád můžete použít nástroj, který je spojí k sobě, jako například tento gem, každopádně vás musím varovat, že pokud přesunete CSS někam jinam, může to mít negativní účinky. Nikdy nevíte, jestli je pořadí důležité.
Další četba:
Pokud se vám Sass Guidelines líbí, zvažte, prosím, jeho podporu.
Podpořit Sass GuidelinesProměnné
Proměnné jsou esencí každého programovacího jazyka. Díky nim můžeme znovu použít hodnoty místo jejich kopírování znovu a znovu. Ale hlavně se díky nim dá jednoduše aktualizovat hodnota. Už žádné další find and replace nebo ruční procházení.
Každopádně CSS není nic jiného než velký koš obsahující všechny naše vejce. Oproti většině jazyků, v CSS nenajdete žádné pravé scopy.
Moje rada proto je taková, abyste proměnné vytvářeli jen když to dává smysl. Neberte to na lehkou váhu, protože to vám v ničem nepomůže. Nová proměnná by se měla vytvářet pouze pokud se splňují následující kritéria:
- hodnota se opakuje minimálně dvakrát;
- hodnota by se mohla alespoň jednou aktualizovat;
- všechny shody výskytu hodnoty jsou vázané s proměnnou (tedy nejsou to náhody).
V podstatě deklarovat proměnnou, která se nikdy nebude aktualizovat nebo je použita pouze na jednom místě, nemá žádný význam.
Scopování
Scopování proměnné v Sassu se během let změnilo. Donedávna byla deklarace proměnné spolu se styly a dalšími skopy lokální již v základu. Každopádně když tu byla již ta samá globální proměnná se stejným názvem, lokální přirovnání mohlo změnit globální proměnnou. Od verze 3.4 Sass řeší koncept scopů správně a vytváří namísto toho novou lokální proměnnou.
V dokumentaci se hovoří o stínování globální proměnné. Pokud deklarujete proměnnou, která již existuje, v globálním scopu v vnitřním prostoru (selektor, funkce, mixin…), lokální proměnná stíňuje tu globální. V podstatě ji přepíše jen pro daný scope.
Následující útržka kódu vysvětluje koncept stíňování proměnné.
// Initialize a global variable at root level.
$variable: 'initial value';
// Create a mixin that overrides that global variable.
@mixin global-variable-overriding {
$variable: 'mixin value' !global;
}
.local-scope::before {
// Create a local variable that shadows the global one.
$variable: 'local value';
// Include the mixin: it overrides the global variable.
@include global-variable-overriding;
// Print the variable’s value.
// It is the **local** one, since it shadows the global one.
content: $variable;
}
// Print the variable in another selector that does no shadowing.
// It is the **global** one, as expected.
.other-local-scope::before {
content: $variable;
}
// Initialize a global variable at root level.
$variable: 'initial value'
// Create a mixin that overrides that global variable.
@mixin global-variable-overriding
$variable: 'mixin value' !global
.local-scope::before
// Create a local variable that shadows the global one.
$variable: 'local value'
// Include the mixin: it overrides the global variable.
+global-variable-overriding
// Print the variable’s value.
// It is the **local** one, since it shadows the global one.
content: $variable
// Print the variable in another selector that does no shadowing.
// It is the **global** one, as expected.
.other-local-scope::before
content: $variable
značka !default
Pokud vytváříte knihovnu, framework, grid systém nebo jakoukoli jinou část Sassu, která se bude zveřenovat a používat externími vývojáři, všechny konfigurační proměnné by měly být označeny značkou !default
, takže budou moci být přepsány.
$baseline: 1em !default;
$baseline: 1em !default
Díky tomu může vývojář definovat vlastní $baseline
proměnnou před importováním vaší knihovny a neuvidí svou proměnnou přepsanou.
// Developer’s own variable
$baseline: 2em;
// Your library declaring `$baseline`
@import 'your-library';
// $baseline == 2em;
// Developer’s own variable
$baseline: 2em
// Your library declaring `$baseline`
@import your-library
// $baseline == 2em
značka !global
Značka !global
by se měla používat pro přepisování globálních proměnných z lokálního scopu. Pokud definujete proměnnou v kořenové úrovni, značka !global
by se však měla vynechat.
// Yep
$baseline: 2em;
// Nope
$baseline: 2em !global;
// Yep
$baseline: 2em
// Nope
$baseline: 2em !global
Více proměnných nebo mapy
Používání map spíše než více proměnných má několik výhod. Největší výhoda je možnost provést smyčku nad mapou, což s rozdílnými proměnnými nelze.
Další plus pro používání map je možnost vytvořit malou getter funkci pro přátelštější API. Zvažte například následující Sass kód:
/// Z-indexes map, gathering all Z layers of the application
/// @access private
/// @type Map
/// @prop {String} key - Layer’s name
/// @prop {Number} value - Z value mapped to the key
$z-indexes: (
'modal': 5000,
'dropdown': 4000,
'default': 1,
'below': -1,
);
/// Get a z-index value from a layer name
/// @access public
/// @param {String} $layer - Layer’s name
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
@return map-get($z-indexes, $layer);
}
/// Z-indexes map, gathering all Z layers of the application
/// @access private
/// @type Map
/// @prop {String} key - Layer’s name
/// @prop {Number} value - Z value mapped to the key
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)
/// Get a z-index value from a layer name
/// @access public
/// @param {String} $layer - Layer’s name
/// @return {Number}
/// @require $z-indexes
@function z($layer)
@return map-get($z-indexes, $layer)
Extend
Direktiva @extend
je právě jedna z funkcí Sassu, co jej udělalo tak populárním již několik let zpátky. Jen připomenu, že to umožňuje říci Sassu, aby nastyloval element A tak, aby to odpovídalo selektoru B. Netřeba asi dodávat, že tato funkce může ztratit svou hodnotu, pokud píšete modulární CSS.
Každopádně mám pocit, že vás musím před touto funkcí varovat. Stejně tak, jak je to chytré, tak je @extend
stále ošemetný koncept, který by mohl udělat více škody, než-li užitku, zvláště když se špatně použije. Věc se má tak, že když extendujete selektor, nemůžete zodpovědět následující otázky bez toho, aniž byste měli nějakou hlubokou znalost celé codebase:
- kde se můj aktuální selektor připojí?
- mohu způsobovat nežádoucí efekty?
- jak velké CSS vyjde z tohoto jednoho extendu?
Všichni víte, že výsledek se může pohybovat od ‘nic to nedělá’ až po katastrofální vedlejší účinky. A právě proto je moje první rada vyhnout se nadobro @extend
direktivě. Může to znít brutálně, ale na konci dne to může ušetřit nějaké ty bolesti hlavy a potíže.
Jak již bylo řečeno, znáte rčení:
Nikdy neříkej nikdy.
— Zřejmě ne Beyonce.
Samozřejmě existují případy, kde by extendování selektorů mohlo být k užitku, přesto ale vždy mějte na paměti tyto pravidla, abyste se nedostali do potíží:
- Použijte extend z modulu, ne napříč různými moduly.
- Použijte extend na samostatné placeholdery, nikoli na skutečné selektory.
- Ujistěte se, že placeholder, který extendujete, je ve stylech přítomný co možná nejméně.
Pokud se rozhodnete použít extend, dovolte mi připomenout, že si to moc dobře nerozumí s @media
bloky. Jak asi víte, Sass není schopen extendnout vnější selektor z media query. Pokud tak učiníte, kompilátor se jednoduše zhroutí a řekne vám, že takovéto věci nemůžete dělat. Nic moc, zejména proto, že media queries téměř všichni známe.
%button {
display: inline-block;
// … button styles
// Relationship: a %button that is a child of a %modal
%modal > & {
display: block;
}
}
.button {
@extend %button;
}
// Yep
.modal {
@extend %modal;
}
// Nope
.modal {
@extend %modal;
> .button {
@extend %button;
}
}
%button
display: inline-block
// … button styles
// Relationship: a %button that is a child of a %modal
%modal > &
display: block
.button
@extend %button
// Yep
.modal
@extend %modal
// Nope
.modal
@extend %modal
> .button
@extend %button
Nemůžete použít @extend z vnějšího selektoru v rámci @media.
Můžete použít pouze @extend selektory v rámci stejné direktivy.
Často se říká, že @extend
pomáhá s velikostí souboru, jelikož kombinuje selektory a neduplikuje vlastnosti. To je sice pravda, nicméně jakmile použijete Gzip, který provede svou kompresi, rozdíl je zanedbatelný.
Jak bylo řečeno, pokud nemůžete použít Gzip (nebo nic ekvivalentního), pak používání @extend
přístupu nemusí být až tak špatné, dokud však víte, co děláte.
Abych to shrnul, nedoporučoval bych používat @extend
direktivu, mimo nějaké specifické okolnosti, ale nezajdu až tak daleko, abych ji úplně zakázal.
Další četba:
Mixiny
Mixiny jsou jednou z nejvíce používaných funkcí celého Sassu. Jsou klíčem pro znovupoužitelnost a DRY komponenty. A to z dobrých důvodů: mixiny dovolují autorům definovat styly, které mohou být použity napříč styly bez potřeby využívat nesémantické třídy jako .float-left
.
Mohou obsahovat všechny CSS pravidla a v podstatě cokoliv, co je dovoleno používat kdekoli jinde v Sassu. Dokonce mohou přijímat argumenty, přesně jako funkce. Netřeba říkat, že možností je nekonečno.
Ale mám pocit, že vás musím varovat před zneužitím moci mixinů. Opět platí, že klíčové slovo je jednoduchost. Mohli byste se zlákat vytvořit extrémně mocné mixiny s velkým množstvím logiky. Tomu se říká přeinženýrování a trpí tím většina vývojářů. Nepřeceňujte svůj kód a držte jej především jednoduchý. Pokud skončíte s mixinem, který má více než 20 řádků, nebo tak nějak, pak by měl být rozdělen na menší části nebo zcela přepracován.
Základy
Jak již bylo řečeno, mixiny jsou extrémně užitečné a měli byste nějaké používat. Pokud je nějaká skupina vlastností, které se z nějakého důvodu zobrazují spolu (a není to tedy náhoda), můžete si je dát do mixinu. Například micro-clearfix hack od Nicolase Gallaghera si zaslouží být vložen do mixinu.
/// Helper to clear inner floats
/// @author Nicolas Gallagher
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix {
&::after {
content: '';
display: table;
clear: both;
}
}
/// Helper to clear inner floats
/// @author Nicolas Gallagher
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix
&::after
content: ''
display: table
clear: both
Dalším příkladem může být mixin pro nastavení velikosti elementu, který bude definovat with
a height
ve stejném okamžiku. Nejenom, že by bylo psát kód jednodušší, ale také by se lépe četl.
/// Helper to size an element
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
/// Helper to size an element
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
=size($width, $height: $width)
width: $width
height: $height
Další četba:
Seznam argumentů
Pokud se máte v mixinu utkat s neznámým počtem argumentů, vždy použijte spíše arglist
než-li seznam. O arglist
můžete přemýšlet jako o 8. skrytém nezdokumentovaném data typu ze Sassu, který se implicitně používá při průchodu libovolného počtu argumentů mixinu nebo funkce, kde se využívá ...
.
@mixin shadows($shadows...) {
// type-of($shadows) == 'arglist'
// …
}
=shadows($shadows...)
// type-of($shadows) == 'arglist'
// …
Nyní, při vytváření mixinu, který akceptuje několik argumentů (tím myslím 3 a více), přemýšlejte dvakrát před jejich spojením do seznamu nebo mapy, jelikož si myslíte, že je bude jednodušší zpracovat, než s jeden po druhém.
Sass je vlastně pěkně chytrý, co se deklarace mixinů a funkcí týče. Tak moc, že vlastně můžete předat seznam nebo mapu jako arglist funckci/mixinu, a ten si to naparsuje jako sérii argumentů.
@mixin dummy($a, $b, $c) {
// …
}
// Yep
@include dummy(true, 42, 'kittens');
// Yep but nope
$params: (true, 42, 'kittens');
$value: dummy(nth($params, 1), nth($params, 2), nth($params, 3));
// Yep
$params: (true, 42, 'kittens');
@include dummy($params...);
// Yep
$params: (
'c': 'kittens',
'a': true,
'b': 42,
);
@include dummy($params...);
=dummy($a, $b, $c)
// …
// Yep
+dummy(true, 42, 'kittens')
// Yep but nope
$params: (true, 42, 'kittens')
$value: dummy(nth($params, 1), nth($params, 2), nth($params, 3))
// Yep
$params: (true, 42, 'kittens')
+dummy($params...)
// Yep
$params: ('c': 'kittens', 'a': true, 'b': 42,)
+dummy($params...)
Další četba:
Mixiny a vendor prefixy
Mohlo by být lákavé, udělat si vlastní mixin, který vám bude přidávat vendor prefixy pro nepodporovatelné, nebo částečně podporované, CSS vlastnosti. Ale to není to, co chceme. Za prvé, pokud můžete použít Autoprefixer, použijte Autoprefixer. Díky němu nebudete muset v Sassu psát přebyteční kód a ten bude vždy aktuální a vždy udělá lepší práci, než-li vaše prefixující věci.
Bohužel vždy není možné Autoprefixer použít. Pokud používáte Bourbon nebo Compass, asi již pravděpodobně víte, že oba mají kolekci mixinů, které se o vendor prefixy starají. Použijte je.
Pokud nemůžete použít Autoprefixer ani Bourbon nebo Compass, pak a jen tehdy můžete použít svůj vlastní mixin, který se s prefixováním CSS vlastností popere. Ale, prosím vás, nedělejte pro každou vlastnost svůj vlastní mixin, který ručně vypíše každý vendor.
// Nope
@mixin transform($value) {
-webkit-transform: $value;
-moz-transform: $value;
transform: $value;
}
// Nope
=transform($value)
-webkit-transform: $value
-moz-transform: $value
transform: $value
Udělejte to chytře.
/// Mixin helper to output vendor prefixes
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - Unprefixed CSS property
/// @param {*} $value - Raw CSS value
/// @param {List} $prefixes - List of prefixes to output
@mixin prefix($property, $value, $prefixes: ()) {
@each $prefix in $prefixes {
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
/// Mixin helper to output vendor prefixes
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - Unprefixed CSS property
/// @param {*} $value - Raw CSS value
/// @param {List} $prefixes - List of prefixes to output
=prefix($property, $value, $prefixes: ())
@each $prefix in $prefixes
-#{$prefix}-#{$property}: $value
#{$property}: $value
Použití takového mixinu pak bude velmi jednoduché:
.foo {
@include prefix(transform, rotate(90deg), ('webkit', 'ms'));
}
.foo
+prefix(transform, rotate(90deg), ('webkit', 'ms'))
Prosím, vemte na vědomí, že je to velmi špatné řešení. Například se to nemůže vypořádat se složitými polyfily, jako ty, co jsou potřeba pro Flexbox. V tomto případně by bylo použití Autoprefixeru daleko lepší řešení.
Další četba:
Podmíněné příkazy
Pravděpodobně již víte, že Sass poskytuje podmíněné příkazy pomocí @if
a @else
direktiv. V běžných stylech nejsou podmíněné příkazy potřeba, ledaže máte střední až velmi komplexní řešení. Ve skutečnosti existují hlavně pro knihovny a frameworky.
Každopádně, pokud se někdy ocitnete v situaci, kdy je budete využívat, respektujte, prosím, následující zásady:
- Žádné závorky, pokud nejsou nezbytné;
- Vždy mějte prázdný řádek před
@if
; - Vždy ukončete řádek po otevírací závorce (
{
); @else
příkaz mějte na stejném řádku, jako předchozí uzavírací závorka (}
).- Vždy mějte nový prázdný řádek za poslední uzavírací závorkou (
}
), pokud není na dalším řádku uzavírací závorka (}
).
// Yep
@if $support-legacy {
// …
} @else {
// …
}
// Nope
@if ($support-legacy == true) {
// …
}
@else {
// …
}
// Yep
@if $support-legacy
// …
@else
// …
// Nope
@if ($support-legacy == true)
// …
@else
// …
Pokud testujete nepravdivé hodnoty, vždy použijte klíčové slovo not
spíše než testování oproti false
nebo null
.
// Yep
@if not index($list, $item) {
// …
}
// Nope
@if index($list, $item) == null {
// …
}
// Yep
@if not index($list, $item)
// …
// Nope
@if index($list, $item) == null
// …
Vždy dávejte část s proměnnou na levou stranu příkazu a (ne)očekávaný výsledek na stranu pravou. Obrácené podmíněné příkazy jsou často obtížně čitelné, zvláště pro nezkušené vývojáře.
// Yep
@if $value == 42 {
// …
}
// Nope
@if 42 == $value {
// …
}
// Yep
@if $value == 42
// …
// Nope
@if 42 == $value
// …
Při použití podmíněného příkazu v rámci funkce pro vrácení rozdílného výsledku na základě nějaké podmínky se vždy ujistěte, že funkce obsahuje @return
také mimo jakýkoliv podmíněný blok.
// Yep
@function dummy($condition) {
@if $condition {
@return true;
}
@return false;
}
// Nope
@function dummy($condition) {
@if $condition {
@return true;
} @else {
@return false;
}
}
// Yep
@function dummy($condition)
@if $condition
@return true
@return false;
// Nope
@function dummy($condition)
@if $condition
@return true
@else
@return false
Pokud se vám Sass Guidelines líbí, zvažte, prosím, jeho podporu.
Podpořit Sass GuidelinesCykly
Protože Sass umožňuje komplexní datové struktury jako seznamy a mapy, není až takové překvapení, že také umožňuje tyto struktury procházet.
Každopádně, přítomnost cyklů obvykle implikuje středně složitou logiku, která do Sassu pravděpodobně nepatří. A tedy proto se před tím, než-li cyklus použijete, ujistěte, že dává smysl a opravdu řeší problém.
Each
Cyklus @each
je definitivně nejpoužívanější z Sass cyklů. Poskytuje čisté API pro procházení seznamu nebo mapy.
@each $theme in $themes {
.section-#{$theme} {
background-color: map-get($colors, $theme);
}
}
@each $theme in $themes
.section-#{$theme}
background-color: map-get($colors, $theme)
Pokud procházíte mapu, vždy používejte $key
a $value
jako jména proměnných, abyste zachovali konzistentnost.
@each $key, $value in $map {
.section-#{$key} {
background-color: $value;
}
}
@each $key, $value in $map
.section-#{$key}
background-color: $value
Také se ujistěte, že dodržujete tyto pokyny, pro zachování čitelnosti:
- Nový řádek vždy před
@each
; - Nový řádek vždy po ukončující závorce (
}
), tedy pokud další řádek není ukončující závorka (}
).
For
Cyklus @for
může být užitečný, pokud kombinujete CSS pseudo třídu :nth-*
. Kromě tohoto případu preferujte spíše cyklus @each
, pokud musíte něco procházet.
@for $i from 1 through 10 {
.foo:nth-of-type(#{$i}) {
border-color: hsl($i * 36, 50%, 50%);
}
}
@for $i from 1 through 10
.foo:nth-of-type(#{$i})
border-color: hsl($i * 36, 50%, 50%)
Vždy používejte $i
jako jméno proměnné, abyste se drželi obecné konvence, tedy pokud nemáte jiný dobrý důvod proč tak neučinit. Nikdy nepoužívejte klíčové slovo to
, vždy používejte through
. Mnoho vývojářů ani neví, že Sass má tuto možnost a používání může vést k záměně.
Také respektujte tyto pokyny pro zachování čitelnosti:
- Nový řádek vždy před
@for
; - Nový řádek vždy po ukončující závorce (
}
), tedy pokud další řádek není ukončující závorka (}
).
While
Cyklus @while
nemá v Sassu absolutně žádné reálné použití, zvláště když tu není žádná možnost, jak breaknout cyklus zevnitř. Nepoužívejte ho.
Varování a chyby
Pokud bych měl vybrat jednu funkci, která je často Sass vývojáři přehlížena, je to nepochybně možnost dynamického výstupu chyb a varování. Sass obsahuje tři vlastní direktivy pro výpis obsahu ve standardním výstupu systému (CLI, kompilování applikace…), což může být pro někoho překvapením.
@debug
;@warn
;@error
.
Pojďme dát @debug
stranou, protože je jasně určená pro ladění SassScriptu, což nás teď nezajímá. Zbyly nám tedy @warn
a @error
, které jsou shodné až na to, že jedna zastavuje kompilátor, zatímco druhá ne. Schválně hádejte, která je která.
V Sass projektu je nespočet využití pro varování a chyby. V podstatě každý mixin nebo funkce očekávající specifický typ argumentu může vyhazovat chyby, pokud se něco pokazí, nebo zobrazit varování, pokud je pro chybu předpoklad.
Další četba:
Varování
Vezměte si tuto funkci z Sass-MQ, která se pokouší převést px
hodnotu na em
hodnotu, například:
@function mq-px2em($px, $base-font-size: $mq-base-font-size) {
@if unitless($px) {
@warn 'Assuming #{$px} to be in pixels, attempting to convert it into pixels.';
@return mq-px2em($px + 0px);
} @else if unit($px) == em {
@return $px;
}
@return ($px / $base-font-size) * 1em;
}
@function mq-px2em($px, $base-font-size: $mq-base-font-size)
@if unitless($px)
@warn 'Assuming #{$px} to be in pixels, attempting to convert it into pixels.'
@return mq-px2em($px + 0px)
@else if unit($px) == em
@return $px
@return ($px / $base-font-size) * 1em
Pokud je hodnota bezjednotková, funkce předpokládá, že je hodnota vyjádřena pixely. Na tomto místě může být předpoklad riskantní, a proto by měl být uživatel varován, že software provedl něco, co by mohlo být považováno za neočekávané.
Chyby
Chyby, oproti varováním, zabraňují kompilátoru běžet dále. V podstatě zastaví kompilaci a zobrazí zprávu ve výstupním proudu, stejně jako trasování zásobníku, což je užitečné pro debugování. Kvůli tomu by chyby měly vyhodit výjimku, pokud není žádná možnost jak program udržet v chodu. Pokud je to možné, snažte se s problémem pracovat a namísto toho zobrazit varování.
Například pojďme říci, že vytváříte getter funkci pro přístup k hodnotám ze specifické mapy. Můžete vyhodit error, pokud v mapě není požadovaný klíč.
/// Z-indexes map, gathering all Z layers of the application
/// @access private
/// @type Map
/// @prop {String} key - Layer’s name
/// @prop {Number} value - Z value mapped to the key
$z-indexes: (
'modal': 5000,
'dropdown': 4000,
'default': 1,
'below': -1,
);
/// Get a z-index value from a layer name
/// @access public
/// @param {String} $layer - Layer's name
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
@if not map-has-key($z-indexes, $layer) {
@error 'There is no layer named `#{$layer}` in $z-indexes. '
+ 'Layer should be one of #{map-keys($z-indexes)}.';
}
@return map-get($z-indexes, $layer);
}
/// Z-indexes map, gathering all Z layers of the application
/// @access private
/// @type Map
/// @prop {String} key - Layer's name
/// @prop {Number} value - Z value mapped to the key
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)
/// Get a z-index value from a layer name
/// @access public
/// @param {String} $layer - Layer's name
/// @return {Number}
/// @require $z-indexes
@function z($layer)
@if not map-has-key($z-indexes, $layer)
@error 'There is no layer named `#{$layer}` in $z-indexes. '
+ 'Layer should be one of #{map-keys($z-indexes)}.'
@return map-get($z-indexes, $layer)
Nástroje
Co je opravdu hezké na CSS preprocesoru tak populárním jako Sass je to, že přichází s celým ekosystémem frameworků, pluginů, knihoven a nástrojů. Po 8 letech existence se dostáváme blíže a blíže k bodu, kde všechno co může být napsané v Sassu, je napsané v Sassu.
Každopádně mojí radou je udržet počet závislostí na opravdové minimum. Spravování závislostí je tak trochu peklo, kterého nechcete být součástí. A navíc ani žádné externí závislosti nepotřebujete.
Compass
Compass je hlavní Sass framework široko daleko. Vyvíjen Chrisem Eppsteinem, jedním ze dvou hlavních designérů Sassu, a pokud chcete znát můj názor, nemyslím si, že by měl v nejbližší době dramaticky ztratit popularitu.
Já osobně Compass už nepoužívám a hlavním důvodem je právě to, že zpomaluje Sass, a to dost. Ruby Sass je docela pomalé samo o sobě a přidáním více Ruby a více Sassu tomu opravdu moc nepomáhá.
Věc se má tak, že používáme jen velmi málo z celého frameworku. Compass je obrovský. A mixiny na podporu různých prohlížečů jsou jen špičkou ledovce. Matematické funkce, helpery pro obrázky, sprity… Je toho tak moc, co se s tímto skvělým kusem softwaru dá udělat.
Bohužel, všechno je to jen cukříček a není tam žádná zabijácká funkce. Vyjímkou by mohla být udělena pro sprite builder, který je opravdu skvělý, ale Grunticon a Grumpicon dělají stejnou práci a mají výhodu, že mohou být připojeny v procesu sestavení.
Každopádně, používat Compass vám nezakazuji, i když bych jej ani nedoporučil, zvláště jelikož není kompatibilní s LibSass (i když v tomto směru bylo vyvinuto značné úsilí). Pokud máte pocit, že byste jej raději použili, proč ne, ale nemyslím si, že toho v konečném důsledku hodně získáte.
Ruby Sass v současné době prochází několika optimalizacemi, které jsou specificky zamířené na těžkou logiku s mnoha funkcemi a mixinami. Mělo by to dramaticky zlepšit výkon k takovému stavu, že by použití Compassu a dalších frameworků nemuselo Sass zpomalovat.
Další četba:
- Compass
- Sass Frameworks: Compass or Bourbon
- Why I don’t use Compass anymore
- Is Compass to Sass with jQuery is to JavaScript?
Grid systém
Nepoužívat grid systém v dnešní době, kdy je všude Responzivní Web Design, prostě není možnost. Chcete-li, aby návrhy vypadaly konzistentně a pevně ve všech velikostech, použijte nějaký grid pro rozložení elementů. Abyste se vyhnuli nutnosti kódovat tento grid tak, aby fungoval, znovu a znovu dokola, a někteří chytráci dokonce udělali ty své znovupoužitelné.
Nechte mě to ujasnit: nejsem velký fanoušek grid systémů. Samozřejmě vidím jejich potenciál, ale myslím si, že většina z nich jsou totální přestřely a jsou spíše používány na kreslení červených sloupců na bílé pozadí hloupých prezentací designérů. Kdy naposledy jste si říkali děkuji-Bohu,-že-mám-tento-nástroj-pro-budování-2-5-3.1-π-gridu? No právě, nikdy, protože ve většině případů jste chtěli jen normální 12-sloupcový grid, prostě nic úchvatného.
Pokud ve svém projektu používáte CSS framework jako Bootstrap nebo Foundation, pak jsou šance, že již obsahují grid systém opravdu vysoké. V tomto případě bych vám doporučil, abyste jej využili, abyste se zbavili další závislosti.
Pokud nejste vázáni na konkrétní grid systém, budete rádi, že tu jsou dva prvotřídní Sass grid enginy: Susy a Singularity. Oba dělají trochu více, než budete kdy potřebovat, takže si můžete vybrat ten, který preferujete více a buďte si jisti, že všechny vaše krajní případy — dokonce i ty nejzáludnější — budou pokryty. Pokud se ptáte mě, Susy má o něco lepší komunitu, ale to je jen můj názor.
Nebo můžete jít do něčeho trochu více formálního, jako csswizardry-grids. Ať už si vyberete jak si vyberete, volba nebude mít na váš styl kódování téměř žádný dopad, takže je to jen na vás.
Další četba:
- Susy
- Build Web Layouts Easily with Susy
- A Complete Tutorial to Susy 2
- Sass Grids: From Neat to Susy
- Bootstrap’s Grid System vs Susy: a Comparison
- How to Use Susy: Superpowered Sass Grids
- A Creative Grid System with Sass and calc()
SCSS-lint
Lintování kódu je velmi důležité. Obvykle dodržování pravidel z příručky pomáhá redukovat množství kódu, které snižuje kvalitu, ale nikdo není dokonalí a vždy jsou věci, které se dají vylepšit. Dá se říci, že lintování kódu je stejně tak důležité, jako komentování.
SCSS-lint je nástroj, který vám pomáhá udržovat SCSS soubory čisté a čitelné. Je plně přizpůsobitelný a jednoduchý na začlenění do vlastních nástrojů.
SCSS-lint doporučení jsou naštěstí velmi podobné k těm, které jsou popsány v tomto dokumentu. Chcete-li konfigurovat SCSS-link podle Sass Guidelines, doporučuji vám toto nastavení:
linters:
BangFormat:
enabled: true
space_before_bang: true
space_after_bang: false
BemDepth:
enabled: true
max_elements: 1
BorderZero:
enabled: true
convention: zero
ChainedClasses:
enabled: false
ColorKeyword:
enabled: true
ColorVariable:
enabled: false
Comment:
enabled: false
DebugStatement:
enabled: true
DeclarationOrder:
enabled: true
DisableLinterReason:
enabled: true
DuplicateProperty:
enabled: false
ElsePlacement:
enabled: true
style: same_line
EmptyLineBetweenBlocks:
enabled: true
ignore_single_line_blocks: true
EmptyRule:
enabled: true
ExtendDirective:
enabled: false
FinalNewline:
enabled: true
present: true
HexLength:
enabled: true
style: short
HexNotation:
enabled: true
style: lowercase
HexValidation:
enabled: true
IdSelector:
enabled: true
ImportantRule:
enabled: false
ImportPath:
enabled: true
leading_underscore: false
filename_extension: false
Indentation:
enabled: true
allow_non_nested_indentation: true
character: space
width: 2
LeadingZero:
enabled: true
style: include_zero
MergeableSelector:
enabled: false
force_nesting: false
NameFormat:
enabled: true
convention: hyphenated_lowercase
allow_leading_underscore: true
NestingDepth:
enabled: true
max_depth: 1
PlaceholderInExtend:
enabled: true
PrivateNamingConvention:
enabled: true
prefix: _
PropertyCount:
enabled: false
PropertySortOrder:
enabled: false
PropertySpelling:
enabled: true
extra_properties: []
PropertyUnits:
enabled: false
PseudoElement:
enabled: true
QualifyingElement:
enabled: true
allow_element_with_attribute: false
allow_element_with_class: false
allow_element_with_id: false
SelectorDepth:
enabled: true
max_depth: 3
SelectorFormat:
enabled: true
convention: hyphenated_lowercase
class_convention: '^(?:u|is|has)\-[a-z][a-zA-Z0-9]*$|^(?!u|is|has)[a-zA-Z][a-zA-Z0-9]*(?:\-[a-z][a-zA-Z0-9]*)?(?:\-\-[a-z][a-zA-Z0-9]*)?$'
Shorthand:
enabled: true
SingleLinePerProperty:
enabled: true
allow_single_line_rule_sets: false
SingleLinePerSelector:
enabled: true
SpaceAfterComma:
enabled: true
SpaceAfterPropertyColon:
enabled: true
style: one_space
SpaceAfterPropertyName:
enabled: true
SpaceAfterVariableColon:
enabled: true
style: at_least_one_space
SpaceAfterVariableName:
enabled: true
SpaceAroundOperator:
enabled: true
style: one_space
SpaceBeforeBrace:
enabled: true
style: space
allow_single_line_padding: true
SpaceBetweenParens:
enabled: true
spaces: 0
StringQuotes:
enabled: true
style: single_quotes
TrailingSemicolon:
enabled: true
TrailingZero:
enabled: true
TransitionAll:
enabled: false
UnnecessaryMantissa:
enabled: true
UnnecessaryParentReference:
enabled: true
UrlFormat:
enabled: false
UrlQuotes:
enabled: true
VariableForProperty:
enabled: false
VendorPrefixes:
enabled: true
identifier_list: base
include: []
exclude: []
ZeroUnit:
enabled: true
Pokud chcete SCSS lint začlenit do vašeho Grunt build procesu, budete rádi vědět, že pro to existuje Grunt plugin, který se nazývá grunt-scss-lint.
Stejně tak pokud hledáte elegantní aplikace, které pracují s SCSS-lintem a tak podobně, lidé z Thoughtbot (Bourbon, Neat…) pracují na Hound.
Další četba:
TL;DR
Abych to shrnul, chceme:
- Dvě (2) mezery pro odsazení, ne taby;
- 80 znaků široké řádky;
- Správně psané víceřádkové CSS;
- Smysluplné užití whitespaců;
- Řetězce a URL v jednoduchý uvozovkách;
- Žádné koncové mezery, povinná 0 před desetinnou čárkou;
- Nezobrazujte zbytečné 0, zobrazujte úvodní 0;
- Výpočty zabalen v závorkách;
- Žádné magické čísla;
- Barvy vyjádřené v klíčových slovech > HSL > RGB > hexadecimálně;
- Listy oddělené čárkami;
- Nepoužívat koncové čárky v seznamech (jelikož jsou jednořádkové);
- Koncová čárka v mapách;
- Nenořte selektory vyjma pseudo tříd a pseudo elementů;
- Čárkou-oddelené pojmenování;
- Rozsáhlé komentáře;
- Komentáře poháněné SassDoc API;
- Omezené použití
@extend
; - Jednoduché mixiny;
- Tak málo cyklů jak je možno, žádné
@while
; - Snížený počet závislostí;
- Smysluplné použití varování a chyb.
Pokud se vám Sass Guidelines líbí, zvažte, prosím, jeho podporu.
Podpořit Sass Guidelines
Komentování
CSS je ošemetný jazyk plný hacků a podivností. Díky tomu by měl být hodně komentován, zvláště pokud vy nebo někdo jiný zamýšlíte číst a upravovat kód za 6 měsíců nebo rok. Nenechte se, nebo někoho jiného, dostat do pozice Já-jsem-tohle-pane-bože-nenapsal.
I přesto, že se CSS může zdát jednoduché, je mnoho situací, kdy může komentář hodně vysvětlit. Mohou vysvětlit takové věci jako:
A pravděpodobně jsem ještě zapomněl mnoho dalších důvodů. Komentování zabere málo času, když se dělá plynule při psaní kódu, takže jej dělejte ve správný čas. Vracet se zpátky okomentovat kus kódu není nejen zcela nereálné, ale je to zároveň příšerně otravné.
Psaní komentářů
Nejlepší je, když každé CSS pravidlo předchází předchází komentář ve stylu jazyka C, který vysvětluje smysl CSS bloku. Tento komentář může také obsahuje očíslované vysvětlení pro specifické části pravidel. Například:
V podstatě všechno co není zřejmé na první pohled, by mělo být okomentováno. Není tu nic takového jako přiliš mnoho dokumentace. Pamatujte, že nemůžete komentovat zas tak mnoho, takže nažhavte klávesy a pište komentáře pro všechno, co za to stojí.
Pokud komentujete Sass specifickou sekci, použijte Sass řádkové komentáře namísto blokových komentářů ve stylu jazyka C. To zapříčiní, že se komentář nezobrazí ve výstupu, dokonce i v expanded módu během vývoje.
Další četba:
Dokumentace
Každá proměnná, funkce, mixin a placeholder, která je zamýšlena býti znovupoužitelná v codebase by měla být dokumentována jako část globálního API využívající SassDoc.
Jsou vyžadovány tři lomítka (
/
).SassDoc má dvě hlavní role:
Zde je příklad rozsáhle dokumentovaného mixinu se SassDoc:
Další četba: