Zasada CSSSelektory

Specyficzność

Waga selektora, która decyduje, która reguła wygra, gdy kilka reguł ustawia tę samą właściwość tego samego elementu.

Na tej stronie

Przykład

#
CSS
/* (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;
}
Podgląd

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

#
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ł

#
  • .note vs p

    (0, 1, 0) > (0, 0, 1)

    Klasa waży więcej niż selektor typu, więc tło jest zielone, choć reguła p stoi niżej.
  • #intro vs .note.demo

    (1, 0, 0) > (0, 2, 0)

    Jeden identyfikator wygrywa z dowolną liczbą klas. Tło jest niebieskie.
  • .demo vs .note

    (0, 1, 0) = (0, 1, 0)

    Remis. Przy równej wadze wygrywa reguła zapisana później, więc tło jest zielone.
  • :where(#intro) vs p

    (0, 0, 0) < (0, 0, 1)

    :where() zeruje wagę, więc stojąca niżej reguła z identyfikatorem przegrywa z samym p. Tło jest zielone.
  • :is(p, #brak) vs .note

    (1, 0, 0) > (0, 1, 0)

    :is() bierze wagę najmocniejszego selektora z listy, nawet gdy element pasuje przez słabsze p. Tło jest niebieskie.
  • !important

    waga bez znaczenia

    !important wygrywa ze zwykłą deklaracją bez względu na wagę selektora. Tło jest zielone mimo identyfikatora.
  • style=""

    atrybut style

    Styl wpisany w atrybut style jest mocniejszy od każdego selektora w arkuszu. Tło jest zielone.

Pojedynki reguł w praktyce

#

.note vs p

Klasa waży więcej niż selektor typu, więc tło jest zielone, choć reguła p stoi niżej.
.note { background: seagreen; }
p { background: crimson; }

#intro vs .note.demo

Jeden identyfikator wygrywa z dowolną liczbą klas. Tło jest niebieskie.
#intro { background: royalblue; }
.note.demo { background: crimson; }

.demo vs .note

Remis. Przy równej wadze wygrywa reguła zapisana później, więc tło jest zielone.
.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=""

Styl wpisany w atrybut style jest mocniejszy od każdego selektora w arkuszu. Tło jest zielone.
#intro { background: royalblue; }

Więcej przykładów

#
Naprawa: obniżenie wagi przez :where()
CSS
/* (0, 0, 1): :where() zeruje wagę #menu */
:where(#menu) a {
  color: #a1a1aa;
}

/* (0, 1, 0): teraz wygrywa */
.active {
  color: #fbbf24;
}
Podgląd

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. !important rozwią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

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.