CSS pseudo-třídy: nth-child, nth-of-type, nth-last-of-type

Thu, 23 Mar 2017 20:05:27 +1100

Článek z oboru slibuji už dlouho. A čím lepším pokračovat, než pořádným seznamem tipů a triků, jak snáz stylovat web. Dnes se podíváme některé pseudo-třídy kaskádových stylů, které vám usnadní stylování dlouhých seznamů. Ale i krátkých. Také se pokusím vysvětlit, proč tyto selektory nefungují vždy tak, jak bychom si představovali.

HTML kód

Mějme následující HTML kód. Ten může reprezentovat například výpis produktů na e-shopu, výpis novinek nebo čehokoli jiného. Container obsahuje prvky .item zakončené vyčištěním floatů.








Nth-child: základ

Pro ty z nás, kteří si v životě nezapamatují, jestli odd nebo even je lichá nebo sudá, existuje velice jednoduchý vzorec. Každý druhý prvek je samozřejmě sudý, při odečtení jedničky od sudého čísla vyjde číslo liché.

.itemlist .item:nth-child(2n) {background:red;}
.itemlist .item:nth-child(2n-1) {background:blue;}

Rozsah: od začátku po N-tý

Často potřebujeme pár prvních elementů odlišit od těch ostatních. Takto zvýrazníme první 3.

.itemlist .item:nth-child(-n+3) {background:blue;}

Rozsah: od N-tého dál

Pokud potřebujeme opak výše uvedeného, učiníme tak následovně.

.itemlist .item:nth-child(n+4) {background:blue;}

Rozsah: průnik definic

.itemlist .item:nth-child(-n+6):nth-child(n+4) {background:blue;}

Nth-child: kdy to nefunguje

Při použití n-tého potomka je důležité myslet na jednu věc: pseudo-selektor se nevztahuje k CSS třídě, u které je napsán. Takže pokud někam mezi divy vložíme například nějaké , celý princip pořadí prvků se rozbije.

Následující zápisy jsou ekvivalentní:

.itemlist .item:nth-child(2n) {background:blue;}
.itemlist :nth-child(2n) {background:blue;}

Proč se tedy mnohem častěji setkáme s podobou zápisu na prvním řádku než na druhém? Odpověď je jednoduchá: přece aby bylo jasné, co tím autor myslel. K čemu přesně je definice myšlena. Druhý řádek proto považuji za monstrózní prasárnu.

Nth-of-type

Nth-of-type částečně supluje chování, kterého většinou chceme u podobných výpisů dosáhnout. Na rozdíl od nth-child, která referuje na N-tý prvek DOMu nezávisle na tom, o jaký prvek se jedná, nth-of-type se vztahuje na tagName. Takže když si rozšíříme první příklad o nějaké další prázdné prvky, fungovat to bude.








Pokud selektor napojíme na .item, zacílí právě divy. Ostatní tagy stejného rodiče ignoruje. Samozřejmě v takovém případě nechceme čistící prvek jako div, nýbrž jako span.

.itemlist .item:nth-of-type(2n) {background:blue;}

Nth-last-of-type

Má stejný princip jako u předchozího selektoru, akorát prvky bereme odzadu. Tady je opravdu nutné dbát na jména tagů, protože zobrazení se pak může různě přeskakovat či neaplikovat vůbec. Jako příklad uvedu HTML kód se spoustou parazitních tagů, kterým zobrazení definovat nechceme.








.itemlist .item:nth-of-type(3n+1) {background:blue;}
.itemlist .item:nth-last-of-type(1) {background:red;}
.itemlist .item:nth-last-of-type(2n) {background:green;}

První, čtvrtý a sedmý prvek bude modrý. Poslední bude červený. A každý sudý odzadu zase zelený, což samozřejmě přebije modré pozadí prvku čtvrtého :-)

N-tý prvek v závislosti na rozlišení

Na závěr si dáme trochu responzivity. Produktové výpisy s různým počtem prvků podle rozlišení dnes najdeme na každém druhém webu. Možností nastylování je spousta a já bych na závěr představil jednu z nich, samozřejmě za využití nth-of-type. Abychom nemuseli vše 10x redefinovat, omezíme definice rozlišením.

Nejdřív budou na stránce 4 prvky vedle sebe, pak 3 a na závěr 2. A jako malý bonus obarvíme každý druhý řádek jinou barvou. (Tedy skupinu záznamů na daném řádku.) HTML kód bude opět stejný, jako v první ukázce, akorát tam toho bude trochu víc.








Každý 4. element bude mít zresetovaný pravý margin, každý 4+1. zresetuje float. Každý 5., 6., 7. a 8. prvek bude zvýrazněný. Skrz omezení na plus a mínus bohužel komplexnější funkci nenapíšeme, a tak je potřeba to takhle vylistovat za sebou.

.itemlist {max-width:900px;margin:0 auto;}
.itemlist .cleaner {clear:both;}
.itemlist .item {width:24.25%;margin:0 1% 10px 0;float:left;height:50px;background:grey;}

@media all and (min-width: 1201px){
	.itemlist .item:nth-of-type(4n) {margin-right:0%;}
	.itemlist .item:nth-of-type(4n+1) {clear:both;}

	.itemlist .item:nth-of-type(8n),
	.itemlist .item:nth-of-type(8n-1),
	.itemlist .item:nth-of-type(8n-2),
	.itemlist .item:nth-of-type(8n-3) {
		background:blue;
	}
}

@media all and (min-width: 601px) and (max-width: 1200px){
	.itemlist .item {width:32.666%;}
	.itemlist .item:nth-of-type(3n) {margin-right:0%;}
	.itemlist .item:nth-of-type(3n+1) {clear:both;}

	.itemlist .item:nth-of-type(6n),
	.itemlist .item:nth-of-type(6n-1),
	.itemlist .item:nth-of-type(6n-2) {
		background:blue;
	}
}

@media all and (max-width: 600px){
	.itemlist .item {width:49.5%;}
	.itemlist .item:nth-of-type(2n) {margin-right:0%;}
	.itemlist .item:nth-of-type(2n+1) {clear:both;}

	.itemlist .item:nth-of-type(4n),
	.itemlist .item:nth-of-type(4n-1) {
		background:blue;
	}
}

Pokud jsme nuceni jednotlivé prvky cílit nějakým šíleným kaskádovým zápisem, lze stejnou definici zapsat i negací bez nutnosti opakovat 4x pod sebou ".itemlist .item". Ale to už trochu zavání výstižným "WTF" (kde počet WTF za minutu je neoficiální ukazatel kvality kódu).

Odkazy na ukázky najdete na konci článku.

html.project-237 body.default-article.has-productlist
 .container.dark-bg .central-area .itemlist
 .item:not(:nth-of-type(8n+1)):not(:nth-of-type(8n+2)):not(:nth-of-type(8n+3)):not(:nth-of-type(8n+4)){
	background:blue;
}

Ukázky uvedených řešení

Vše, co jsme v dnešním článku vyzkoušeli, si můžete prohlédnout na následujících odkazech. Druhý příklad pak reaguje na resize okna prohlížeče.

:nth-child, :nth-of-type 1. - 6. příklad
:nth-of-type responzivní ukázka