Zgodność ze specyfikacją

Podcast CSS – 003: szczegółowość

Załóżmy, że pracujesz z tymi kodami HTML i CSS:

<button class="branding">Hello, Specificity!</button>
.branding {
  color: blue;
}

button {
  color: red;
}

Są tu 2 reguły, które kierują na ten sam element. Każda reguła zawiera deklarację, która ma ustawić kolor przycisku: jedna próbuje ustawić kolor czerwony, a druga – niebieski. Która deklaracja zostanie zastosowana do elementu?

Zrozumienie algorytmu szczegółowości CSS jest kluczem do zrozumienia, jak CSS decyduje między konkurującymi deklaracjami.

Szczegółowość to jeden z odrębnych etapów kaskady, który został omówiony w ostatnim module dotyczącym kaskady.

Ocena szczegółowości

Każda reguła selektora w źródle otrzymuje ocenę. Szczegółowość można traktować jako łączny wynik, a każdy typ selektora dodaje punkty do tego wyniku. Deklaracje z reguł o najwyższej szczegółowości wygrywają.

W przypadku szczegółowości w prawdziwym projekcie należy zadbać o to, aby reguły CSS, które mają być stosowane, rzeczywiście były stosowane, a jednocześnie utrzymywać niskie wyniki, aby uniknąć złożoności. Szczegółowość powinna być tylko tak wysoka, jak jest to konieczne, a nie jak najwyższa. W przyszłości może być konieczne zastosowanie ważniejszych reguł CSS. Jeśli wybierzesz najwyższą szczegółowość, utrudnisz sobie to zadanie.

Szczegółowość nie jest liczbą dziesiętną, ale triadą składającą się z 3 komponentów: A, B i C.

  • A: szczegółowość podobna do identyfikatora
  • B: szczegółowość podobna do klasy
  • C: szczegółowość podobna do elementu

Często jest ona reprezentowana za pomocą notacji (A,B,C). Na przykład: (1,0,2). Powszechnie używana jest też notacja alternatywna A-B-C.

Diagram przedstawiający 3 składniki specyficzności (A,B,C). W przypadku każdego komponentu diagram pokazuje, co on reprezentuje, oraz przykładowe selektory, które na niego wpływają.
Diagram przedstawiający, na który komponent szczegółowości wpływają poszczególne selektory.

Porównywanie szczegółowości

Szczegółowości są porównywane przez porównanie 3 komponentów w kolejności: szczegółowość z większą wartością A jest bardziej szczegółowa; jeśli 2 wartości A są równe, to szczegółowość z większą wartością B jest bardziej szczegółowa; jeśli 2 wartości B są również równe, to szczegółowość z większą wartością C jest bardziej szczegółowa; jeśli wszystkie wartości są równe, to 2 szczegółowości są równe.

Na przykład (1,0,0) jest uważana za wyższą szczegółowość niż (0,4,3) ponieważ wartość A w (1,0,0) (czyli 1) jest większa niż wartość A w (0,4,3) (czyli 0).

Selektory wpływają na szczegółowość

Każda część triady szczegółowości zaczyna się od wartości 0, więc domyślna szczegółowość to (0,0,0). Każda część selektora zwiększa szczegółowość, która w zależności od typu selektora zwiększa wartość A, B lub C.

Selektor uniwersalny

Selektor uniwersalny (*) **nie dodaje szczegółowości** , pozostawiając jej wartość na początkowej szczegółowości (0,0,0).

* {
  color: red;
}

Selektor elementu lub pseudoelementu

Selektor elementu (typu) lub pseudoelementu dodaje szczegółowość podobną do elementu, która zwiększa komponent C o 1.

Poniższe przykłady mają ogólną szczegółowość (0,0,1).

Selektor typu

div {
  color: red;
}

Selektor pseudoelementu

::selection {
  color: red;
}

Selektor klasy, pseudoklasy lub atrybutu

Selektor klasy, pseudoklasy lub atrybutu dodaje szczegółowość podobną do klasy , która zwiększa komponent B o 1.

Poniższe przykłady mają szczegółowość (0,1,0).

Selektor klasy

.my-class {
  color: red;
}

Selektor pseudoklasy

:hover {
  color: red;
}

Selektor atrybutu

[href='#'] {
  color: red;
}

Selektor identyfikatora

Selektor identyfikatora dodaje szczegółowość podobną do identyfikatora, która zwiększa komponent A o 1, o ile używasz selektora identyfikatora (#myID), a nie selektora atrybutu ([id="myID"]).

W poniższym przykładzie szczegółowość wynosi (1,0,0).

#myID {
  color: red;
}

Inne selektory

CSS ma wiele selektorów. Nie wszystkie z nich dodają szczegółowość. Na przykład pseudoklasa :not() sama w sobie nie dodaje nic do obliczania szczegółowości.

Szczegółowość pseudoklasy :not() jest zastępowana szczegółowością najbardziej szczegółowego selektora w jej rozdzielonym przecinkami argumencie selektorów, co daje taką samą szczegółowość, jakby została zapisana jako :not(:is(argument)).

div:not(.my-class) {
  color: red;
}

Pseudoklasa :is() również nie dodaje nic do obliczania szczegółowości. Podobnie jak :not() przyjmuje szczegółowość najbardziej szczegółowego argumentu.

:is(h1, h2, h3) {
  color: blue;
}

Ten przykład ma szczegółowość (0,0,1), ponieważ ma tylko 1 rodzaj selektora (type).

Po dodaniu id szczegółowość wzrasta do (1,0,0).

:is(h1, h2, h3, #my-heading) {
  color: blue;
}

Pseudoklasa :where() jest inna. Niezależnie od szczegółowości dowolnego z jej argumentów zawsze ma szczegółowość (0,0,0).

:where(h1, h2, h3, #my-heading) {
  color: blue;
}

Style o niskiej szczegółowości stosowane za pomocą :where() pozwalają zastąpić te style podstawowymi selektorami w dalszej części arkusza stylów:

:where(#my-content) {
   color: red;
}

p {
   color: blue;
}

Mimo że :where() ma id na liście argumentów, nadal ma tylko szczegółowość (0, 0, 0), więc podstawowy selektor p ją zastępuje, a tekst będzie blue.

Sprawdź swoją wiedzę

Sprawdź swoją wiedzę na temat oceny szczegółowości

Jaka jest szczegółowość a[href=/learn/css/%22#%22%5D%3C%2Fcode>?

(0,0,1)
Wartość a to (0,0,1), ale wartość [href=/learn/css/%22#%22%5D%3C%2Fcode> to (0,1,0).
(0,1,0)
Spróbuj jeszcze raz. Wartość a to (0,0,1), ale wartość [href=/learn/css/%22#%22%5D%3C%2Fcode> to (0,1,0).
(0,1,1)
Wartość a to (0,0,1), a wartość [href=/learn/css/%22#%22%5D%3C%2Fcode> to (0,1,0), co daje łączną szczegółowość (0,1,1).

Czynniki, które nie wpływają na szczegółowość

Istnieje kilka powszechnych błędnych przekonań dotyczących wpływu tych czynników na szczegółowość.

Wbudowane atrybuty stylów

CSS stosowany bezpośrednio do atrybutu style elementu, nie wpływa na szczegółowość, ponieważ jest to inny etap kaskady który jest oceniany przed szczegółowością.

<div style="color: red"></div>

Aby zastąpić tę deklarację w arkuszu stylów, musisz sprawić, aby deklaracja wygrała na wcześniejszym etapie kaskady.

Możesz na przykład dodać !important do niej, aby stała się częścią źródła !important utworzonego przez autora.

Deklaracje !important

!important na końcu deklaracji CSS nie wpływa na szczegółowość ale umieszcza deklarację w innym źródle, czyli utworzonym przez autora !important.

W poniższym przykładzie szczegółowość .my-class nie ma znaczenia dla wygrania deklaracji !important.

.my-class {
  color: red !important;
  color: white;
}

Gdy 2 deklaracje są !important, szczegółowość ponownie wchodzi w grę, ponieważ etap źródła w kaskadzie nie był w stanie jeszcze określić zwycięzcy.

.branding {
  color: blue !important;
}

button {
  color: red !important;
}

Szczegółowość w kontekście

Gdy używany jest złożony selektor, każda jego część dodaje się do szczegółowości. Rozważ ten przykład kodu HTML:

<a class="my-class another-class" href="#">A link</a>

Ten link ma 2 klasy. Reguła w tym kodzie CSS ma szczegółowość (0,0,1):

a {
  color: red;
}

Jeśli odwołasz się do jednej z klas w selektorze, będzie on miał szczegółowość (0,1,1):

a.my-class {
  color: green;
}

Dodaj do selektora drugą klasę, a będzie on miał szczegółowość (0,2,1):

a.my-class.another-class {
  color: rebeccapurple;
}

Dodaj do selektora atrybut href, a będzie on miał szczegółowość (0,3,1):

a.my-class.another-class[href] {
  color: goldenrod;
}

Na koniec dodaj do tego :hover pseudoklasę, a selektor będzie miał szczegółowość (0,4,1):

a.my-class.another-class[href]:hover {
  color: lightgrey;
}

Sprawdź swoją wiedzę

Sprawdź swoją wiedzę na temat oceny szczegółowości

Który z tych selektorów ma szczegółowość (0,2,1)?

article > section
Elementy dodają szczegółowość podobną do elementu (komponent `C`). W selektorze są 2 elementy, co daje szczegółowość (0,0,2).
article.card.dark
Elementy dodają szczegółowość podobną do elementu (komponent `C`), a klasy dodają szczegółowość podobną do klasy (komponent `B`). Dzięki 2 klasom i 1 elementowi ten selektor ma szczegółowość (0,2,1).
article:hover a[href]
Elementy dodają szczegółowość podobną do elementu (komponent `C`), a pseudoklasy i atrybuty dodają szczegółowość podobną do klasy (komponent `B`). Są tu 2 selektory elementów (2 × (0,0,1)), selektor atrybutu (wartość (0,1,0)) i selektor klasy (wartość (0,1,0)). Daje to łączną szczegółowość (0,2,2).

Praktyczne zwiększanie szczegółowości

Załóżmy, że masz taki kod CSS:

.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

Z takim kodem HTML:

<button class="my-button" onclick="alert('hello')">Click me</button>

Przycisk ma szare tło, ponieważ drugi selektor ma szczegółowość (0,1,1). Wynika to z tego, że ma on 1 selektor typu (button), który ma wartość (0,0,1) , oraz selektor atrybutu ([onclick]), który ma wartość (0,1,0).

Poprzednia reguła – .my-button – ma wartość (0,1,0) , ponieważ ma 1 selektor klasy, który ma niższą szczegółowość niż (0,1,1).

Jeśli chcesz zwiększyć szczegółowość tej reguły, możesz powtórzyć selektor klasy w ten sposób:

.my-button.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

Teraz przycisk będzie miał niebieskie tło, ponieważ nowy selektor ma szczegółowość (0,2,0).

W przypadku remisu w szczegółowości następuje powrót do następnego etapu kaskady

Na razie kontynuujmy przykład z przyciskiem i zmieńmy kod CSS na ten:

.my-button {
  background: blue;
}

[onclick] {
  background: grey;
}

Przycisk ma szare tło, ponieważ oba selektory mają identyczną szczegółowość (0,1,0).

Jeśli zmienisz kolejność reguł w kodzie źródłowym, przycisk będzie niebieski.

[onclick] {
  background: grey;
}

.my-button {
  background: blue;
}

Wynika to z tego, że oba selektory mają taką samą szczegółowość. W tym przypadku kaskada wraca do etapu kolejności występowania.

Zasoby