Le podcast CSS – 003 : Spécificité
Supposons que vous utilisiez le code HTML et CSS suivant :
<button class="branding">Hello, Specificity!</button>
.branding {
color: blue;
}
button {
color: red;
}
Ici, deux règles ciblent le même élément. Chaque règle contient une déclaration qui vise à définir la couleur du bouton : l'une essaie de colorer le bouton en rouge et l'autre en bleu. Quelle déclaration est appliquée à l'élément ?
Pour comprendre comment le CSS fait son choix entre des déclarations concurrentes, vous devez comprendre l'algorithme de spécificité CSS.
La spécificité est l'une des étapes distinctes de la cascade, qui a été abordée dans le dernier module, sur la cascade.
Calcul de la spécificité
Chaque règle de sélecteur dans une origine reçoit un score. Vous pouvez considérer la spécificité comme un score total, et chaque type de sélecteur rapporte des points à ce score. Les déclarations des règles ayant la spécificité la plus élevée sont prioritaires.
Dans un projet réel, la spécificité consiste à s'assurer que les règles CSS que vous souhaitez appliquer s'appliquent réellement, tout en maintenant généralement des scores bas pour éviter la complexité. La spécificité ne doit être aussi élevée que nécessaire, plutôt que de viser la spécificité la plus élevée possible. À l'avenir, il peut être nécessaire d'appliquer un CSS plus important. Si vous optez pour la spécificité la plus élevée, vous rendrez cette tâche difficile.
La spécificité n'est pas un nombre décimal, mais une triade composée de trois composants : A, B et C.
A: spécificité de type IDB: spécificité de type classeC: spécificité de type élément
Elle est souvent représentée à l'aide de la notation (A,B,C). Exemple : (1,0,2).
La notation alternative A-B-C est également couramment utilisée.
Comparer les spécificités
Les spécificités sont comparées en comparant les trois composants dans l'ordre : la spécificité avec une valeur A plus élevée est plus spécifique ; si les deux valeurs A sont identiques, la spécificité avec une valeur B plus élevée est plus spécifique ; si les deux valeurs B sont également identiques, la spécificité avec une valeur C plus élevée est plus spécifique ; si toutes les valeurs sont identiques, les deux spécificités sont égales.
Par exemple, (1,0,0) est considéré comme une spécificité plus élevée que (0,4,3)
car la valeur A dans (1,0,0) (qui est 1)
est supérieure à la valeur A de (0,4,3) (qui est 0).
Les sélecteurs influencent la spécificité
Chaque partie de la triade de spécificité commence par une valeur de 0,
la spécificité par défaut est donc (0,0,0).
Chaque partie d'un sélecteur augmente la spécificité qui, selon le type de sélecteur, incrémente la valeur de A, B ou C.
Sélecteur universel
Un sélecteur universel (*)
n'ajoute aucune spécificité, laissant sa valeur à la spécificité initiale de (0,0,0).
* {
color: red;
}
Sélecteur d'élément ou de pseudo-élément
Un sélecteur d'élément (type)
ou de pseudo-élément
ajoute une spécificité de type élément qui incrémente le composant C de 1.
Les exemples suivants ont une spécificité globale de (0,0,1).
Sélecteur de type
div {
color: red;
}
Sélecteur de pseudo-élément
::selection {
color: red;
}
Sélecteur de classe, de pseudo-classe ou d'attribut
Un sélecteur de classe,
pseudo-classe ou
d'attribut ajoute une spécificité de type classe
qui incrémente le composant B de 1.
Les exemples suivants ont une spécificité de (0,1,0).
Sélecteur de classe
.my-class {
color: red;
}
Sélecteur de pseudo-classe
:hover {
color: red;
}
Sélecteur d'attribut
[href='#'] {
color: red;
}
Sélecteur d'ID
Un sélecteur d'
ID ajoute une spécificité de type ID qui incrémente le composant A de 1,
à condition d'utiliser un sélecteur d'ID (#myID) et non un sélecteur d'attribut ([id="myID"]).
Dans l'exemple suivant, la spécificité est (1,0,0).
#myID {
color: red;
}
Autres sélecteurs
Le CSS comporte de nombreux sélecteurs. Ils n'ajoutent pas tous de spécificité.
Par exemple, la :not() pseudo-classe
elle-même n'ajoute rien au calcul de la spécificité.
La spécificité de la pseudo-classe :not() est remplacée par la spécificité du sélecteur le plus spécifique dans son argument de sélecteurs séparés par une virgule, ce qui donne la même spécificité que si elle avait été écrite :not(:is(argument)).
div:not(.my-class) {
color: red;
}
La pseudo-classe :is()
n'ajoute pas non plus au calcul de la spécificité. Comme :not(), elle prend la spécificité de son argument le plus spécifique.
:is(h1, h2, h3) {
color: blue;
}
Cet exemple a une spécificité de (0,0,1) , car il ne comporte qu'un seul type de sélecteur (type).
Avec l'ajout d'un id, la spécificité passe à (1,0,0).
:is(h1, h2, h3, #my-heading) {
color: blue;
}
La :where() pseudo-classe
est différente. Quelle que soit la spécificité de l'un de ses arguments, elle a toujours une spécificité de (0,0,0).
:where(h1, h2, h3, #my-heading) {
color: blue;
}
Les styles de faible spécificité appliqués à l'aide de :where() vous permettent de remplacer ces styles par des sélecteurs de base plus tard dans votre feuille de style :
:where(#my-content) {
color: red;
}
p {
color: blue;
}
Même si :where() comporte un id dans sa liste d'arguments, sa spécificité n'est que de (0, 0, 0). Le sélecteur p de base le remplace donc et le texte sera blue.
Vérifiez vos connaissances
Testez vos connaissances sur le calcul de la spécificité
Quelle est la spécificité de a[href="#"] ?
(0,0,1)a vaut (0,0,1), mais le [href="#"] vaut (0,1,0).(0,1,0)a vaut (0,0,1), mais le [href="#"] vaut (0,1,0).(0,1,1)a vaut (0,0,1) et le [href="#"] vaut (0,1,0), ce qui donne une spécificité totale de (0,1,1).Facteurs qui n'affectent pas la spécificité
Il existe des idées fausses courantes concernant l'incidence des facteurs suivants sur la spécificité.
Attributs de style intégrés
Le CSS appliqué directement à l'attribut style d'un élément,
n'affecte pas la spécificité, car il s'agit d'une étape différente de la cascade
qui est évaluée avant la spécificité.
<div style="color: red"></div>
Pour remplacer cette déclaration à partir d'une feuille de style, vous devez recourir à pour que la déclaration soit prioritaire à une étape antérieure de la cascade.
Par exemple, vous pouvez ajouter !important pour qu'il fasse partie de l'origine !important créée.
Déclarations !important
Un !important à la fin d'une déclaration CSS n'affecte pas la spécificité
mais place la déclaration dans une origine différente,
à savoir Authored !important.
Dans l'exemple suivant, la spécificité de .my-class n'est pas pertinente pour que la déclaration !important soit prioritaire.
.my-class {
color: red !important;
color: white;
}
Lorsque deux déclarations sont !important, la spécificité entre à nouveau en jeu, car l'étape d'origine de la cascade n'a pas encore pu déterminer le gagnant.
.branding {
color: blue !important;
}
button {
color: red !important;
}
Spécificité en contexte
Lorsqu'un sélecteur complexe ou composé est utilisé, chaque partie de ce sélecteur s'ajoute à la spécificité. Prenons l'exemple de code HTML suivant :
<a class="my-class another-class" href="#">A link</a>
Ce lien comporte deux classes.
La règle du CSS suivant a une spécificité de (0,0,1) :
a {
color: red;
}
Si vous référencez l'une des classes dans le sélecteur,
sa spécificité est désormais de (0,1,1) :
a.my-class {
color: green;
}
Ajoutez l'autre classe au sélecteur,
sa spécificité est désormais de (0,2,1) :
a.my-class.another-class {
color: rebeccapurple;
}
Ajoutez l'attribut href au sélecteur,
sa spécificité est désormais de (0,3,1) :
a.my-class.another-class[href] {
color: goldenrod;
}
Enfin, ajoutez une :hover pseudo-classe à tout cela.
Le sélecteur se retrouve avec une spécificité de (0,4,1) :
a.my-class.another-class[href]:hover {
color: lightgrey;
}
Vérifiez vos connaissances
Testez vos connaissances sur le calcul de la spécificité
Lequel des sélecteurs suivants a une spécificité de (0,2,1) ?
article > section(0,0,2).article.card.dark(0,2,1).article:hover a[href](0,0,1)), un sélecteur d'attribut (valeur (0,1,0)) et un sélecteur de classe (valeur (0,1,0)). La spécificité totale de ce sélecteur est donc de (0,2,2).Augmenter la spécificité de manière pragmatique
Supposons que vous ayez un CSS qui ressemble à ceci :
.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Avec un code HTML qui ressemble à ceci :
<button class="my-button" onclick="alert('hello')">Click me</button>
Le bouton a un arrière-plan gris,
car le deuxième sélecteur a une spécificité de (0,1,1).
En effet, il comporte un sélecteur de type (button), qui est (0,0,1) , et un sélecteur d'attribut ([onclick]), qui est (0,1,0).
La règle précédente, .my-button, est égale à (0,1,0) , car elle comporte un sélecteur de classe, qui a une spécificité inférieure à (0,1,1).
Si vous souhaitez donner un coup de pouce à cette règle, vous pouvez répéter le sélecteur de classe comme suit :
.my-button.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
Le bouton aura désormais un arrière-plan bleu, car le nouveau sélecteur obtient une spécificité de (0,2,0).
En cas d'égalité de spécificité, la cascade passe à l'étape suivante
Pour l'instant, reprenons l'exemple du bouton et modifions le CSS comme suit :
.my-button {
background: blue;
}
[onclick] {
background: grey;
}
Le bouton a un arrière-plan gris, car les deux sélecteurs ont une spécificité identique de (0,1,0).
Si vous inversez les règles dans l'ordre source, le bouton devient bleu.
[onclick] {
background: grey;
}
.my-button {
background: blue;
}
En effet, les deux sélecteurs ont la même spécificité. Dans ce cas, la cascade revient à l'étape de l'ordre d'apparition.