Concept CSSSélecteurs

Spécificité

Le poids d’un sélecteur, qui détermine quelle règle gagne lorsque plusieurs règles définissent la même propriété du même élément.

Sur cette page

Exemple

#
CSS
/* (1, 0, 1) */
#menu a {
  color: #a1a1aa;
}

/* (0, 1, 0) : perd, bien qu’écrite plus bas */
.active {
  color: #fbbf24;
}

/* (1, 1, 1) : gagne */
#menu a.active {
  font-weight: 700;
  border-bottom: 2px solid #fbbf24;
}
Aperçu

Le lien actif a le gras et le soulignement de la troisième règle, mais garde sa couleur grise : .active a perdu face au #menu a plus fort.

Définition et utilisation

#

Quand deux règles définissent la même propriété du même élément, le navigateur doit désigner un gagnant. L’un des critères principaux est la spécificité, c’est-à-dire le poids du sélecteur, noté sous la forme de trois nombres (a, b, c) : a est le nombre d’identifiants, b le nombre de classes, d’attributs et de pseudo-classes, et c le nombre de sélecteurs de type et de pseudo-éléments.

Les poids se comparent à partir de la gauche, colonne par colonne. (1, 0, 0) l’emporte sur (0, 15, 0), car la première colonne tranche avant même qu’on regarde la seconde. Ce n’est pas une simple somme de points. Le sélecteur universel * et les combinateurs (espace, >, +, ~) n’ajoutent rien. En cas d’égalité, la règle écrite le plus tard gagne.

Les pseudo-classes fonctionnelles ont leurs propres règles. :is(), :not() et :has() reprennent le poids du sélecteur le plus fort de leur liste, tandis que :where() pèse toujours zéro, ce qui permet d’écrire des styles faciles à écraser. :nth-child(… of S) correspond au poids de la pseudo-classe plus celui du sélecteur le plus fort de S.

D’autres étapes de la cascade se situent au-dessus de la spécificité. Les styles de l’attribut style l’emportent sur tout sélecteur de la feuille de style, et une déclaration avec !important l’emporte sur les déclarations ordinaires, quel que soit le poids du sélecteur (entre plusieurs !important, c’est de nouveau la spécificité qui décide). Les couches @layer fonctionnent de façon similaire : une règle d’une couche plus tardive gagne, même avec un sélecteur plus faible.

Syntaxe

#
Syntaxe
/* spécificité = (a, b, c) */
#id                          /* a : (1, 0, 0) */
.classe  [attribut]  :hover  /* b : (0, 1, 0) */
p  ::before                  /* c : (0, 0, 1) */
*  >  +  ~  :where()         /* sans poids : (0, 0, 0) */

Duels de règles

#
  • .note vs p

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

    Une classe pèse plus qu’un sélecteur de type, donc le fond est vert, même si la règle p est écrite plus bas.
  • #intro vs .note.demo

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

    Un seul identifiant l’emporte sur n’importe quel nombre de classes. Le fond est bleu.
  • .demo vs .note

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

    Égalité. À poids égal, la règle écrite le plus tard gagne, donc le fond est vert.
  • :where(#intro) vs p

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

    :where() ramène le poids à zéro, donc la règle avec l’identifiant, bien qu’écrite plus bas, perd face au simple p. Le fond est vert.
  • :is(p, #missing) vs .note

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

    :is() prend le poids du sélecteur le plus fort de la liste, même quand l’élément correspond via le p plus faible. Le fond est bleu.
  • !important

    le poids n’a pas d’importance

    !important gagne face à une déclaration ordinaire, quel que soit le poids du sélecteur. Le fond est vert malgré l’identifiant.
  • style=""

    attribut style

    Un style écrit dans l’attribut style est plus fort que n’importe quel sélecteur de la feuille de style. Le fond est vert.

Duels de règles en pratique

#

.note vs p

Une classe pèse plus qu’un sélecteur de type, donc le fond est vert, même si la règle p est écrite plus bas.
.note { background: seagreen; }
p { background: crimson; }

#intro vs .note.demo

Un seul identifiant l’emporte sur n’importe quel nombre de classes. Le fond est bleu.
#intro { background: royalblue; }
.note.demo { background: crimson; }

.demo vs .note

Égalité. À poids égal, la règle écrite le plus tard gagne, donc le fond est vert.
.demo { background: royalblue; }
.note { background: seagreen; }

:where(#intro) vs p

:where() ramène le poids à zéro, donc la règle avec l’identifiant, bien qu’écrite plus bas, perd face au simple p. Le fond est vert.
p { background: seagreen; }
:where(#intro) { background: crimson; }

:is(p, #missing) vs .note

:is() prend le poids du sélecteur le plus fort de la liste, même quand l’élément correspond via le p plus faible. Le fond est bleu.
:is(p, #missing) { background: royalblue; }
.note { background: crimson; }

!important

!important gagne face à une déclaration ordinaire, quel que soit le poids du sélecteur. Le fond est vert malgré l’identifiant.
p { background: seagreen !important; }
#intro { background: royalblue; }

style=""

Un style écrit dans l’attribut style est plus fort que n’importe quel sélecteur de la feuille de style. Le fond est vert.
#intro { background: royalblue; }

Plus d’exemples

#
La correction : réduire le poids avec :where()
CSS
/* (0, 0, 1) : :where() ramène le poids de #menu à zéro */
:where(#menu) a {
  color: #a1a1aa;
}

/* (0, 1, 0) : maintenant elle gagne */
.active {
  color: #fbbf24;
}
Aperçu

Une fois #menu enveloppé dans :where(), une simple classe suffit à mettre en valeur le lien actif.

Compatibilité des navigateurs

#

Largement disponible

Fonctionne dans tous les navigateurs modernes, y compris sur mobile. Vous pouvez l’utiliser sans crainte.

  • Chrome
  • Edge
  • Firefox
  • Safari

Bonnes pratiques

#
  • Gardez la spécificité basse et régulière : stylisez surtout avec des classes uniques. Le résultat dépend alors de l’ordre des règles, facile à contrôler.
  • Avant de recourir à !important, vérifiez dans les outils de développement quelle règle gagne et pourquoi. !important résout le problème aujourd’hui, mais imposera demain un autre !important.
  • Enveloppez les styles de base et de bibliothèque dans :where(). Ils ont alors un poids nul, et n’importe qui peut les écraser avec une seule classe.

Entrées associées

#

Vous voyez une erreur ou il manque un exemple ? Écrivez-nous.