Specyficzność
Waga selektora, która decyduje, która reguła wygra, gdy kilka reguł ustawia tę samą właściwość tego samego elementu.
Przykład
#/* (1, 0, 1) */
#menu a {
color: #a1a1aa;
}
/* (0, 1, 0): przegrywa, choć stoi niżej */
.active {
color: #fbbf24;
}
/* (1, 1, 1): wygrywa */
#menu a.active {
font-weight: 700;
border-bottom: 2px solid #fbbf24;
}<nav id="menu" class="stage" style="display: flex; gap: 16px;">
<a href="#" style="text-decoration: none;">Kursy</a>
<a href="#" class="active" style="text-decoration: none;">Dokumentacja</a>
<a href="#" style="text-decoration: none;">Kolekcje</a>
</nav>Aktywny link ma pogrubienie i podkreślenie z trzeciej reguły, ale wciąż szary kolor: .active przegrała z mocniejszym #menu a.
Definicja i zastosowanie
#Gdy dwie reguły ustawiają tę samą właściwość tego samego elementu, przeglądarka musi wybrać zwycięzcę. Jednym z głównych kryteriów jest specyficzność, czyli waga selektora zapisywana jako trzy liczby (a, b, c): a to liczba identyfikatorów, b to liczba klas, atrybutów i pseudoklas, a c to liczba selektorów typu i pseudoelementów.
Wagi porównuje się od lewej, kolumna po kolumnie. (1, 0, 0) wygrywa z (0, 15, 0), bo pierwsza kolumna rozstrzyga, zanim w ogóle spojrzymy na drugą. To nie jest zwykła suma punktów. Selektor uniwersalny * i kombinatory (spacja, >, +, ~) nie dodają nic. Przy remisie wygrywa reguła zapisana później.
Pseudoklasy funkcyjne mają własne zasady. :is(), :not() i :has() przejmują wagę najmocniejszego selektora ze swojej listy, a :where() zawsze waży zero, co pozwala pisać style łatwe do nadpisania. :nth-child(… of S) to waga pseudoklasy plus najmocniejszego selektora z S.
Ponad specyficznością stoją inne etapy kaskady. Style z atrybutu style wygrywają z każdym selektorem w arkuszu, a deklaracja z !important wygrywa ze zwykłymi deklaracjami bez względu na wagę selektora (wśród kilku !important znów decyduje specyficzność). Podobnie działają warstwy @layer: reguła z późniejszej warstwy wygrywa, nawet jeśli ma słabszy selektor.
Składnia
#/* specyficzność = (a, b, c) */
#id /* a: (1, 0, 0) */
.klasa [atrybut] :hover /* b: (0, 1, 0) */
p ::before /* c: (0, 0, 1) */
* > + ~ :where() /* bez wagi: (0, 0, 0) */Pojedynki reguł
#(0, 1, 0) > (0, 0, 1)
Klasa waży więcej niż selektor typu, więc tło jest zielone, choć regułapstoi niżej.(1, 0, 0) > (0, 2, 0)
Jeden identyfikator wygrywa z dowolną liczbą klas. Tło jest niebieskie.(0, 1, 0) = (0, 1, 0)
Remis. Przy równej wadze wygrywa reguła zapisana później, więc tło jest zielone.(0, 0, 0) < (0, 0, 1)
:where()zeruje wagę, więc stojąca niżej reguła z identyfikatorem przegrywa z samymp. Tło jest zielone.(1, 0, 0) > (0, 1, 0)
:is()bierze wagę najmocniejszego selektora z listy, nawet gdy element pasuje przez słabszep. Tło jest niebieskie.waga bez znaczenia
!importantwygrywa ze zwykłą deklaracją bez względu na wagę selektora. Tło jest zielone mimo identyfikatora.atrybut style
Styl wpisany w atrybutstylejest mocniejszy od każdego selektora w arkuszu. Tło jest zielone.
Pojedynki reguł w praktyce
#.note vs p
p stoi niżej..note { background: seagreen; }
p { background: crimson; }#intro vs .note.demo
#intro { background: royalblue; }
.note.demo { background: crimson; }.demo vs .note
.demo { background: royalblue; }
.note { background: seagreen; }:where(#intro) vs p
:where() zeruje wagę, więc stojąca niżej reguła z identyfikatorem przegrywa z samym p. Tło jest zielone.p { background: seagreen; }
:where(#intro) { background: crimson; }:is(p, #brak) vs .note
:is() bierze wagę najmocniejszego selektora z listy, nawet gdy element pasuje przez słabsze p. Tło jest niebieskie.:is(p, #brak) { background: royalblue; }
.note { background: crimson; }!important
!important wygrywa ze zwykłą deklaracją bez względu na wagę selektora. Tło jest zielone mimo identyfikatora.p { background: seagreen !important; }
#intro { background: royalblue; }style=""
style jest mocniejszy od każdego selektora w arkuszu. Tło jest zielone.#intro { background: royalblue; }Więcej przykładów
#/* (0, 0, 1): :where() zeruje wagę #menu */
:where(#menu) a {
color: #a1a1aa;
}
/* (0, 1, 0): teraz wygrywa */
.active {
color: #fbbf24;
}<nav id="menu" class="stage" style="display: flex; gap: 16px;">
<a href="#" style="text-decoration: none;">Kursy</a>
<a href="#" class="active" style="text-decoration: none;">Dokumentacja</a>
<a href="#" style="text-decoration: none;">Kolekcje</a>
</nav>Po opakowaniu #menu w :where() wystarczy zwykła klasa, żeby wyróżnić aktywny link.
Obsługa przeglądarek
#Szeroko dostępne
Działa we wszystkich nowoczesnych przeglądarkach, także na telefonach. Możesz używać bez obaw.
- Chrome
- Edge
- Firefox
- Safari
Dobre praktyki
#- Trzymaj specyficzność nisko i równo: stylizuj głównie pojedynczymi klasami. Wtedy o wyniku decyduje kolejność reguł, którą łatwo kontrolować.
- Zanim sięgniesz po
!important, sprawdź w narzędziach deweloperskich, która reguła wygrywa i dlaczego.!importantrozwiązuje problem dziś, ale jutro wymusi kolejne!important. - Style bazowe i biblioteczne opakuj w
:where(). Mają wtedy wagę zero i każdy nadpisze je jedną klasą.
Powiązane hasła
#- #idWybiera element o podanym identyfikatorze z atrybutu id. Ma bardzo wysoką specyficzność, więc jego reguły trudno potem nadpisać.
- .klasaWybiera elementy, które mają podaną klasę w atrybucie class. Najczęściej używany selektor do stylowania komponentów.
- :where()Działa jak :is(), ale zawsze ma zerową specyficzność. Idealna do stylów bazowych, które łatwo nadpisać.
- :is()Dopasowuje element do dowolnego selektora z listy. Skraca długie, powtarzalne selektory do jednego zapisu.
- :not()Wybiera elementy, które nie pasują do podanego selektora ani do żadnego z listy.
- A, BPrzecinek łączy kilka selektorów w jedną regułę, żeby nadać im te same style bez powtarzania deklaracji.
Widzisz błąd albo brakuje przykładu? Napisz do nas.