Specificità

Il podcast sui CSS - 003: Specificità

Supponiamo di lavorare con il seguente codice HTML e CSS:

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

button {
  color: red;
}

Qui ci sono due regole che hanno come target lo stesso elemento. Ogni regola contiene una dichiarazione che vuole impostare il colore del pulsante: una cerca di colorare il pulsante di rosso e l'altra di blu. Quale dichiarazione viene applicata all'elemento?

Comprendere l'algoritmo di specificità dei CSS è fondamentale per capire come i CSS decidono tra dichiarazioni in conflitto.

La specificità è una delle fasi distinte della cascata, che è stata trattata nell'ultimo modulo, su la cascata.

Punteggio di specificità

Ogni regola del selettore all'interno di un'origine riceve un punteggio. Puoi considerare la specificità come un punteggio totale e ogni tipo di selettore guadagna punti per questo punteggio. Le dichiarazioni delle regole con la specificità più elevata vincono.

Con la specificità in un progetto reale, l'equilibrio consiste nel garantire che le regole CSS che ti aspetti vengano effettivamente applicate, mantenendo in genere i punteggi bassi per evitare la complessità. La specificità deve essere solo quella necessaria, anziché puntare alla massima specificità possibile. In futuro, potrebbe essere necessario applicare alcuni CSS più importanti. Se scegli la massima specificità, renderai difficile questo lavoro.

La specificità non è un numero decimale, ma una triade composta da tre componenti: A, B e C.

  • A: specificità simile all'ID
  • B: specificità simile alla classe
  • C: specificità simile all'elemento

Viene spesso rappresentata utilizzando la notazione (A,B,C). Ad esempio: (1,0,2). Viene comunemente utilizzata anche la notazione alternativa A-B-C.

Un diagramma che mostra i tre componenti della specificità (A,B,C). Per ogni componente, il diagramma mostra cosa rappresenta e alcuni selettori di esempio che lo interessano.
Un diagramma che mostra quale componente della specificità influisce su vari selettori.

Come confrontare le specificità

Le specificità vengono confrontate confrontando i tre componenti in ordine: la specificità con un valore A maggiore è più specifica; se i due valori A sono uguali, la specificità con un valore B maggiore è più specifica; se anche i due valori B sono uguali, la specificità con un valore C maggiore è più specifica; se tutti i valori sono uguali, le due specificità sono uguali.

Ad esempio, (1,0,0) è considerata una specificità maggiore di (0,4,3) perché il valore A in (1,0,0) (che è 1) è maggiore del valore A di (0,4,3) (che è 0).

I selettori influenzano la specificità

Ogni parte della triade di specificità inizia con un valore di 0, quindi la specificità predefinita è (0,0,0). Ogni parte di un selettore aumenta la specificità che, a seconda del tipo di selettore, incrementa il valore di A, B o C.

Selettore universale

Un selettore universale (*) **non aggiunge specificità**, lasciando il suo valore alla specificità iniziale di (0,0,0).

* {
  color: red;
}

Selettore di elementi o pseudo-elementi

Un selettore di elementi (tipo) o pseudo-elementi aggiunge specificità simile all'elemento che incrementa il componente C di 1.

I seguenti esempi hanno una specificità complessiva di (0,0,1).

Selettore di tipo

div {
  color: red;
}

Selettore di pseudo-elementi

::selection {
  color: red;
}

Selettore di classi, pseudo-classi o attributi

Un selettore di classi, pseudo-classi o attributi aggiunge specificità simile alla classe che incrementa il componente B di 1.

I seguenti esempi hanno una specificità di (0,1,0).

Selettore di classi

.my-class {
  color: red;
}

Selettore di pseudo-classi

:hover {
  color: red;
}

Selettore di attributi

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

Selettore ID

Un selettore ID aggiunge specificità simile all'ID che incrementa il componente A di 1, a condizione che tu utilizzi un selettore ID (#myID) e non un selettore di attributi ([id="myID"]).

Nell'esempio seguente, la specificità è (1,0,0)

#myID {
  color: red;
}

Altri selettori

I CSS hanno molti selettori. Non tutti aggiungono specificità. Ad esempio, la :not() pseudo-classe non aggiunge nulla al calcolo della specificità.

La specificità della pseudo-classe :not() viene sostituita dalla specificità del selettore più specifico nel suo argomento di selettori separati da virgole, fornendo la stessa specificità di se fosse stato scritto :not(:is(argument)).

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

Anche la :is() pseudo-classe non aggiunge nulla al calcolo della specificità. Come :not(), prende la specificità del suo argomento più specifico.

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

Questo esempio ha una specificità di (0,0,1) perché ha un solo tipo di selettore (type).

Con l'aggiunta di un id, la specificità aumenta a (1,0,0).

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

La :where() pseudo-classe è diversa. Indipendentemente dalla specificità di uno dei suoi argomenti, ha sempre una specificità di (0,0,0).

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

Gli stili a bassa specificità applicati utilizzando :where() ti consentono di sostituire questi stili con selettori di base in un secondo momento nel foglio di stile:

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

p {
   color: blue;
}

Anche se :where() ha un id nell'elenco degli argomenti, ha comunque solo una specificità di (0, 0, 0), quindi il selettore p di base lo sostituisce e il testo sarà blue.

Mettiti alla prova

Verifica la tua conoscenza del punteggio di specificità

Qual è la specificità di a[href="#"]?

(0,0,1)
a vale (0,0,1), ma [href="#"] vale (0,1,0).
(0,1,0)
Riprova. a vale (0,0,1), ma [href="#"] vale (0,1,0).
(0,1,1)
Il a vale (0,0,1) e il [href="#"] vale (0,1,0), per una specificità totale di (0,1,1).

Fattori che non influiscono sulla specificità

Esistono alcuni malintesi comuni sui seguenti fattori che influiscono sulla specificità.

Attributi di stili in linea

I CSS applicati direttamente all'attributo style di un elemento, non influiscono sulla specificità, in quanto si tratta di un passaggio diverso de lla cascata che viene valutato prima della specificità.

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

Per sostituire questa dichiarazione da un foglio di stile, devi ricorrere a far vincere la dichiarazione in un passaggio precedente di cascata.

Ad esempio, puoi aggiungere !important in modo che diventi parte dell'origine !important creata.

Dichiarazioni !important

Un !important alla fine di una dichiarazione CSS non influisce sulla specificità ma inserisce la dichiarazione in un'origine diversaorigine, ovvero Authored !important.

Nell'esempio seguente, la specificità di .my-class non è pertinente per la vittoria della dichiarazione !important.

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

Quando due dichiarazioni sono !important, la specificità entra di nuovo in gioco, poiché il passaggio di origine della cascata non è stato ancora in grado di determinare il vincitore.

.branding {
  color: blue !important;
}

button {
  color: red !important;
}

Specificità nel contesto

Quando viene utilizzato un selettore complesso o composto, ogni parte del selettore si somma alla specificità. Considera questo esempio di HTML:

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

Questo link ha due classi. La regola nei seguenti CSS ha una specificità di (0,0,1):

a {
  color: red;
}

Se fai riferimento a una delle classi nel selettore, ora ha una specificità di (0,1,1):

a.my-class {
  color: green;
}

Aggiungi l'altra classe al selettore, ora ha una specificità di (0,2,1):

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

Aggiungi l'attributo href al selettore, ora ha una specificità di (0,3,1):

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

Infine,aggiungi una :hover pseudo-classe a tutto questo, il selettore finisce per avere una specificità di (0,4,1):

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

Mettiti alla prova

Verifica la tua conoscenza del punteggio di specificità

Quale dei seguenti selettori ha una specificità di (0,2,1)?

article > section
Gli elementi aggiungono specificità simile all'elemento (componente `C`). Nel selettore sono presenti 2 elementi, il che conferisce una specificità di (0,0,2).
article.card.dark
Gli elementi aggiungono specificità simile all'elemento (componente `C`) e le classi aggiungono specificità simile alla classe (componente `B`). Con 2 classi e 1 elemento, questo selettore ha una specificità di (0,2,1).
article:hover a[href]
Gli elementi aggiungono specificità simile all'elemento (componente `C`), le pseudo-classi e gli attributi aggiungono specificità simile alla classe (componente `B`). Sono presenti 2 selettori di elementi (2 × (0,0,1)), un selettore di attributi (che vale (0,1,0)) e un selettore di classi (che vale (0,1,0)). Questo selettore ha una specificità totale di (0,2,2).

Aumentare pragmaticamente la specificità

Supponiamo di avere alcuni CSS simili a questi:

.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

Con HTML simile a questo:

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

Il pulsante ha uno sfondo grigio, perché il secondo selettore ha una specificità di (0,1,1). Questo perché ha un selettore di tipo (button), che è (0,0,1) e un selettore di attributi ([onclick]), che è (0,1,0).

La regola precedente, .my-button, è uguale a (0,1,0) perché ha un selettore di classi, che ha una specificità inferiore a (0,1,1).

Se vuoi dare una spinta a questa regola, puoi ripetere il selettore di classi in questo modo:

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

button[onclick] {
  background: grey;
}

Ora, il pulsante avrà uno sfondo blu, perché il nuovo selettore ottiene una specificità (0,2,0)

In caso di parità di specificità, si torna al passaggio successivo della cascata

Continuando con l'esempio del pulsante, ora modifichiamo i CSS in questo modo:

.my-button {
  background: blue;
}

[onclick] {
  background: grey;
}

Il pulsante ha uno sfondo grigio, perché entrambi i selettori hanno una specificità identica di (0,1,0).

Se inverti le regole nell'ordine di origine, il pulsante diventa blu.

[onclick] {
  background: grey;
}

.my-button {
  background: blue;
}

Questo perché entrambi i selettori hanno la stessa specificità. In questo caso, la cascata torna al passaggio dell'ordine di visualizzazione.

Risorse