Selektory#
Lista selektorów#
E , F { /* deklaracje */ }
Lista selektorów # (selector list) jest listą selektorów oddzielonych od siebie przecinkami (U+002C ,
), która reprezentuje unię wszystkich elementów wybranych przez każdy z poszczególnych selektorów tej listy. Dla przykładu, kiedy w CSS wiele selektorów dzieli te same deklaracje, to można je zgrupować w listę rozdzieloną przecinkami (w dowolnej ilości). Białe znaki wokół ,
są opcjonalne i nie mają specjalnego znaczenia.
Poniższe trzy reguły z identycznymi deklaracjami można zapisać w postaci jednej reguły:
h1 { font-family: sans-serif; }
h2 { font-family: sans-serif; }
h3 { font-family: sans-serif; }
/* jest równoważne */
h1, h2, h3 { font-family: sans-serif; }
Trzeba być świadomym tego, że równoważność zachodzi w przykładzie ponieważ wszystkie selektory są prawidłowe. Jeśli tylko jeden z tych selektorów byłby nieprawidłowy, to cała lista selektorów stałaby się nieważna. Czyli w drugim wariancie reguła dla wszystkich trzech elementów nagłówkowych byłyby nieważna, podczas gdy w pierwszym przypadku tylko reguła jednego z trzech indywidualnych nagłówków byłaby unieważniona.
Rzućmy okiem na kolejny przykład:
h1 { font-family: sans-serif; }
h2..foo { font-family: sans-serif; }
h3 { font-family: sans-serif; }
/* nie jest równoważne */
h1, h2..foo, h3 { font-family: sans-serif; }
Jak pisałem wcześniej, cały selektor h1, h2..foo, h3
jest nieprawidłowy i przypisana reguła stylu jest pomijana. W przypadku niezgrupowanych selektorów tylko reguła dla selektora h2..foo
jest opuszczana.
Prosty przykład:
<!DOCTYPE html>
<html>
<head>
<style>
div, strong {color: blue;}
p, ,div, strong {color: red;} /* błąd w selektorze */
</style>
</head>
<body>
<p>Akapit ma kolor czarny.</p>
<div> Jakiś tekst wewnątrz DIV ma kolor niebieski
<p>Akapit ma kolor niebieski (dziedziczy z DIV), <strong>mocna emfaza ma kolor niebieski</strong>, i znów akapit.</p>
Jakiś tekst wewnątrz DIV ma kolor niebieski
</div>
<p>Akapit ma kolor czarny.</p>
</body>
</html>
Unia poleceń#
Lista selektorów może być argumentem funkcyjnych pseudoklas, np. w pseudoklasie dopasowań lub pseudoklasie negacji. W kontekście programistycznym lista selektorów stanowi unię (union) poleceń. Trzeba dobrze zrozumieć, co właściwie taka wartość oznacza.
Załóżmy, że mamy następującą regułę:
div:not(#box, .heavy) {color: red;} /* poziom 4 */
Będzie ona równoważna zapisowi z poprzedniego modułu:
div:not(#box), div:not(.heavy) {color: red;} /* poziom 3 */
/* i w konsekwencji */
div:not(#box) {color: red;}
div:not(.heavy) {color: red;}
Czyli każdy selektor z listy selektorów wewnątrz pseudoklasy będzie traktowany niezależnie od siebie, tak jakby tworzył osobną regułę. Efektem tego będzie sytuacja, gdzie pierwszy selektor ostyluje element <div class="heavy">
, a drugi selektor ostyluje element <div id="box">
. Zatem, pomimo użycia pseudkoklasy negacji, style i tak zostały przypisane do elementów, które posiadały wyszczególnione wartości wewnątrz :not()
. Jest to jak najbardziej prawidłowe zachowanie w przypadku listy selektorów.
Wraz ze wzrostem liczby funkcyjnych pseudoklas w selektorze (oraz selektorów w ich liście selektorów), ilość możliwych kombinacji ulegnie zwiększeniu:
:not(.class1, .class2) :not(class3, class4) {color: red;}
/* jest równoważne */
:not(.class1) :not(class3) {color: red;}
:not(.class1) :not(class4) {color: red;}
:not(.class2) :not(class3) {color: red;}
:not(.class2) :not(class4) {color: red;}
Oczywiście można łączyć wykluczenia, coś na podobnej zasadzie, jak koniunkcja logiczna (logical conjunction) z języków programowania - każdy cząstkowy warunek musi być prawdziwy, aby całe polecenie miało zastosowanie. Przeanalizujmy kolejną regułę:
div:not(#box.heavy) {color: red;} /* poziom 4 */
Będzie ona równoważna następującemu zapisowi z poprzedniego modułu:
div:not(#box):not(.heavy) {color: red;} /* poziom 3 */
Tym razem żaden z elementów <div id="box">
i <div class="heavy">
nie będzie czerwony.
Warto przypomnieć, że nowy moduł selektorów zezwala na umieszczanie różnego rodzaju selektorów wewnątrz funkcyjnych pseudoklas, co można wykorzystać do bardziej zwięzłego zapisu:
:not([title=val1]):not([title=val2]):not([title=val3]):not([title=val4])
:not([title=val1][title=val2][title=val3][title=val4]
:not([title=val1,val2,val3,val4])
Ostatnia możliwość jest wciąż poddawana dyskusji, i nie wiadomo, czy kiedykolwiek zostanie zatwierdzona. Nie jest też jasne znaczenie samego znaku przecinka w zapisie wielu wartości atrybutu (unia czy koniunkcja).
Oczywiście cały ten opis będzie miał zastosowanie dla dowolnej funkcyjnej pseudoklasy, która przyjmuje listę selektorów jako argument. Warto przeanalizować poniższy przykład użycia pseudoklsy :matches()
, którą ze względu na brak obsługi w aktualnych przeglądarkach, chwilowo zastąpiłem poleceniem :-moz-any()
działającym w Firefoksie:
<!DOCTYPE html>
<html>
<head>
<style>
:-moz-any(.red1, .red2):-moz-any(.red3, .red4) {color: red;}
</style>
</head>
<body>
<p>Akapit powinien mieć kolor czarny (brak przypisanych stylów).</p>
<p class="red1">Akapit powinien mieć kolor czarny (class="red1").</p>
<p class="red3">Akapit powinien mieć kolor czarny (class="red3").</p>
<p class="red1 red2">Akapit powinien mieć kolor czarny (class="red1 red2").</p>
<p class="red3 red4">Akapit powinien mieć kolor czarny (class="red3 red4").</p>
<p class="red1 red3">Akapit powinien mieć kolor czerwony(class="red1 red3").</p>
<p class="red1 red4">Akapit powinien mieć kolor czerwony(class="red1 red4").</p>
<p class="red2 red3">Akapit powinien mieć kolor czerwony(class="red2 red3").</p>
<p class="red2 red4">Akapit powinien mieć kolor czerwony(class="red2 red4").</p>
<p class="red1 red3 next">Akapit powinien mieć kolor czerwony(class="red1 red3 next").</p>
<p class="before red2 red4 next">Akapit powinien mieć kolor czerwony(class="before red2 red4 next").</p>
</body>
</html>