Lekce 1.3

Moderní nativní CSS

Vlastní vlastnosti a zanořování bez preprocesoru, dotazy na velikost rodiče a specificita, kterou máme pod kontrolou.

Selektor :has() a vrstvy kaskády

Dvě novinky, které spolu na první pohled nesouvisejí, ale v praxi se potkávají: jedna se dostane tam, kam to dřív nešlo, druhá pak uklidí nepořádek, který tím může vzniknout ve specificitě.

Rodičovský selektor

Dlouho platilo, že CSS umí hledat jen směrem dolů – od rodiče k potomkovi. Pseudotřída :has() to obrací:

css
/* karta, ve které je obrázek, dostane jiné rozvržení */
.card:has(img) {
  grid-template-columns: 150px 1fr;
}

/* políčko formuláře, ve kterém je neplatná hodnota */
.field:has(input:invalid) {
  border-color: var(--color-danger);
}

Vlevo pravidlo .card .badge: šipka vede z karty dolů na odznak a obarvený je odznak. Vpravo pravidlo .card(.badge): šipka vede taky dolů, obarvená je ale celá karta.

Podmínka pořád hledá dolů, obarví se ale prvek, na kterém stojí. Poprvé se tak dá v CSS říct „udělej něco s prvkem, který uvnitř sebe něco má“ – a spousta věcí, kvůli kterým se dřív sahalo po JavaScriptu, se scvrkne na jeden selektor.

Pozor

:has() si bere specificitu svého nejsilnějšího argumentu. Zápis .card:has(#promo) je proto stejně silný jako selektor na id a přebije skoro všechno ostatní. Tohle je přesně ten druh překvapení, na který se hodí vrstvy z druhé půlky kapitoly.

Vrstvy kaskády

Vrstva je pojmenovaná přihrádka na pravidla. Jejich pořadí se určí tam, kde se poprvé vyjmenují, a od té chvíle platí, že pozdější vrstva vyhrává bez ohledu na specificitu:

css
@layer reset, components, utilities;

@layer components {
  .card .title { color: var(--color-text); }
}

@layer utilities {
  .text-muted { color: var(--color-text-muted); }
}

Tři vrstvy naskládané na sobě: reset dole, components uprostřed, utilities nahoře, se šipkou vzhůru a popiskem „později = silnější“. Vpravo dvě soupeřící pravidla; vyhrává to se slabší specificitou, protože leží v pozdější vrstvě.

Selektor .text-muted má specificitu nižší než .card .title, a přesto vyhraje. Uvnitř jedné vrstvy se pořadí řeší po staru specificitou; mezi vrstvami rozhoduje jejich pořadí. Je to náhrada za !important, jenom se s ní dá žít.

Poznámka

Pravidla, která nejsou v žádné vrstvě, jsou silnější než všechno ve vrstvách. Vypadá to obráceně, než by člověk čekal, ale dává to smysl: nezařazený kód stojí až nad poslední přihrádkou.

V praxi se vrstvy nasazují hlavně tam, kde se potkává cizí knihovna s vlastním kódem. Knihovna dostane vrstvu pod tou naší a rázem přestane překvapovat, aniž by kdokoli musel psát !important nebo přebíjet selektory delšími selektory.

Bonus

Zjistěte v dokumentaci MDN, co udělá !important uvnitř vrstvy. Pořadí vrstev se pro taková pravidla obrací a stojí za to vědět proč.