Une règle de focus qui fonctionnait parfaitement avant une réorganisation de la feuille de style cesse brusquement de s’appliquer sur les liens d’un menu, sans qu’aucune ligne visant directement :focus-visible n’ait été modifiée. La réorganisation en question consistait à regrouper les styles d’un composant de menu en utilisant le nesting CSS natif, disponible dans les moteurs de rendu principaux depuis fin 2023, pour remplacer une série de sélecteurs répétés par une structure imbriquée plus lisible.
Le nesting natif permet d’écrire des règles CSS imbriquées directement, sans préprocesseur, en utilisant implicitement le sélecteur & pour faire référence au sélecteur parent. Ce confort d’écriture a un effet secondaire rarement anticipé : chaque niveau d’imbrication ajoute la spécificité du sélecteur parent à celle de la règle imbriquée, exactement comme le ferait un préprocesseur, mais de façon moins visible puisqu’aucune étape de compilation ne rend le résultat final explicite avant l’exécution dans le navigateur.
La feuille de style avant et après réorganisation
/* Avant : règles à plat */
.menu-principal a {
color: #1a1a2e;
}
.menu-principal a:focus-visible {
outline: 3px solid #0057b7;
}
Cette version initiale fonctionnait sans ambiguïté : la règle de focus, avec une spécificité de deux classes et un pseudo-classe, l’emportait sur toute règle de couleur simple ailleurs dans la feuille de style.
/* Après : nesting natif */
.menu-principal {
& a {
color: #1a1a2e;
&.actif {
color: #0057b7;
font-weight: bold;
}
}
}
Où la spécificité a dérapé

La règle &.actif, imbriquée à deux niveaux sous .menu-principal, hérite implicitement de la spécificité de ses deux ancêtres en plus de sa propre classe .actif, ce qui porte sa spécificité totale à trois classes, soit strictement supérieure à la règle de focus définie séparément avec seulement deux classes et un pseudo-classe. Résultat concret : sur un lien de menu à la fois actif et focalisé au clavier, la couleur bleue de l’état « actif » l’emportait sur la couleur du contour de focus, rendant ce dernier visuellement peu perceptible sur certains fonds, alors que la règle de focus elle-même n’avait pas changé d’une virgule.
Le calcul de spécificité CSS s’exprime classiquement en un triplet (identifiants, classes/attributs/pseudo-classes, éléments). La règle de focus originale totalisait (0,2,1) : deux classes (.menu-principal, implicite du contexte, et a compté comme élément en réalité, donc plutôt (0,1,1) pour la version à plat). La règle imbriquée &.actif, elle, cumule .menu-principal, a (élément) et .actif, portant sa spécificité à (0,2,1), strictement égale ou supérieure selon l’ordre de déclaration dans le fichier source, ce qui suffit à faire basculer la priorité en cas d’égalité, la règle déclarée en second l’emportant.
Comment le repérer rapidement
- Utiliser l’inspecteur du navigateur pour visualiser les règles CSS appliquées à l’élément et leur ordre de priorité affiché (les règles barrées indiquent une priorité perdue)
- Calculer manuellement ou via un outil en ligne la spécificité de chaque sélecteur en cause, en tenant compte de tous les niveaux de nesting traversés
- Vérifier particulièrement les combinaisons entre un état interactif (
:focus-visible,:hover) et un état de contenu (.actif,.selectionne) imbriqués à des profondeurs différentes
Le correctif
.menu-principal {
& a {
color: #1a1a2e;
&.actif {
color: #0057b7;
font-weight: bold;
}
&:focus-visible {
outline: 3px solid #0057b7;
outline-offset: 2px;
}
}
}
Replacer la règle de focus au même niveau d’imbrication que la règle d’état actif, avec un pseudo-classe qui s’ajoute à la spécificité déjà présente, restaure une priorité au moins égale, et l’ordre de déclaration en dernier lui donne l’avantage en cas d’égalité stricte. Une alternative plus robuste consiste à sortir la règle de focus de toute imbrication profonde pour limiter sa dépendance à l’ordre de déclaration.
Depuis ce cas, nous vérifions systématiquement la spécificité calculée de toute règle de focus après une migration vers le nesting natif, plutôt que de nous fier à une relecture visuelle du fichier source.
En résumé
Le nesting CSS natif ne change rien aux règles de spécificité elles-mêmes : il les rend simplement moins visibles à la lecture, puisque chaque niveau d’imbrication ajoute silencieusement la spécificité de ses ancêtres. Une règle de focus qui semblait à l’abri dans une feuille de style à plat peut se retrouver reléguée après une réorganisation en nesting, si une règle d’état imbriquée plus profondément gagne en spécificité sans que personne ne l’ait anticipé. Le calcul de spécificité mérite d’être vérifié explicitement, pas supposé stable, après toute migration de ce type.