Certaines feuilles de style répètent le même préfixe de sélecteur encore et encore, ligne après ligne. :is() et :where() résolvent ce problème en regroupant plusieurs sélecteurs en un seul, tout en se comportant différemment sur un point crucial : la spécificité.
Comprendre cette différence évite des heures de débogage face à une règle qui écrase un style qu'on pensait pourtant protégé.
Définition
:is() et :where() acceptent une liste de sélecteurs séparés par des virgules et les traitent comme une alternative unique. La règle qui les utilise s'applique dès qu'un des sélecteurs de la liste correspond à l'élément.
Regrouper des sélecteurs répétitifs
/* sans :is(), trois sélecteurs répétés */
header h1,
main h1,
footer h1 {
font-family: "Georgia", serif;
}
/* avec :is(), un seul sélecteur regroupé */
:is(header, main, footer) h1 {
font-family: "Georgia", serif;
}Le résultat visuel est strictement identique entre les deux écritures, mais la seconde est plus courte, plus facile à maintenir, et évite le risque d'oublier de mettre à jour l'un des trois sélecteurs si la règle change.
Le piège de la spécificité
C'est ici que les deux syntaxes divergent radicalement. La Spécificité de :is() correspond à celle de son argument le plus fort dans la liste : si la liste contient un id, toute la règle hérite du poids d'un id, même pour les autres sélecteurs de la liste qui sont de simples classes. :where(), à l'inverse, a une spécificité de zéro, quelle que soit la complexité des sélecteurs qu'il regroupe. Une règle écrite avec :where() peut donc être écrasée par n'importe quelle autre règle, même la plus simple, ce qui en fait un outil précieux pour écrire des styles de base facilement surchargeables.
| Syntaxe | Spécificité | Usage typique |
|---|---|---|
:is(...) | Celle du sélecteur le plus fort de la liste | Regrouper sans changer le comportement |
:where(...) | Toujours zéro | Styles de base facilement surchargés |
Un exemple concret du piège
/* la spécificité de :is() ici égale celle de #principal */
:is(#principal, .secondaire) p {
color: navy;
}
/* cette règle plus simple ne pourra PAS l'emporter */
p {
color: crimson;
}Même si l'élément ciblé correspond en réalité à .secondaire et non à #principal, la règle entière hérite du poids de l'id présent dans la liste. C'est ce comportement, souvent mal anticipé, qui rend une règle en :is() étonnamment difficile à surcharger.
:where() à :is(), sauf si vous avez une raison précise de vouloir hériter du poids du sélecteur le plus fort.Quand préférer :not() à :is()
:is() et :not() répondent à des besoins différents. :is() regroupe des alternatives qui doivent toutes déclencher le même style, tandis que :not() exclut un cas précis d'un groupe plus large. Il arrive fréquemment de les combiner dans le même sélecteur, par exemple pour cibler tous les titres sauf ceux situés dans un pied de page, tout en regroupant plusieurs niveaux de titre en une seule règle.
:is(h2, h3, h4):not(footer *) {
scroll-margin-top: 80px;
}Cette règle ajoute une marge de défilement à tous les titres de niveau deux à quatre, sauf ceux qui se trouvent dans le pied de page, en une seule ligne plutôt qu'en plusieurs sélecteurs séparés.
Questions fréquentes
:is() et :where() avec des pseudo-classes comme :hover ?Oui, la liste peut contenir n'importe quel type de sélecteur valide, y compris des pseudo-classes, ce qui permet par exemple de regrouper plusieurs états au sein d'une seule règle.
Oui, la liste peut contenir des sélecteurs composés, comme des combinaisons de classes ou de combinateurs, tant que chaque élément de la liste reste un sélecteur valide en lui-même.
Avec :is(), un sélecteur invalide dans la liste n'invalide pas les autres, la règle continue de fonctionner pour les sélecteurs valides restants, contrairement au comportement d'une liste classique séparée par des virgules dans un sélecteur simple.