Kodokon kodokon.com

Sélecteurs modernes : :has, :is, :where, :nth-child avancé

Exploitez les pseudo-classes fonctionnelles récentes pour sélectionner selon le contenu, regrouper sans exploser la spécificité et cibler des motifs complexes.

9 min · 3 questions

Ouvrir cette leçon dans Kodokon

:is() et :where() regroupent des sélecteurs, mais divergent sur un point décisif : la spécificité. :is(nav, .menu, #main a) prend la spécificité du plus fort de ses arguments (ici l'ID), même si c'est nav qui matche. :where() a une spécificité de zéro, quels que soient ses arguments. Conséquence pratique : :where() est l'outil idéal pour les resets et les styles par défaut d'un design system, que n'importe quel simple sélecteur de classe pourra surcharger sans lutte.

CSS
:where(h1, h2, h3, h4) {
  margin-block: 0;
  line-height: 1.2;
}

:is(article, aside, section) :is(h2, h3) {
  font-family: var(--font-heading);
}

.prose :is(ul, ol) li + li {
  margin-top: 0.5em;
}
Regroupement et contrôle de la spécificité

:has() inverse enfin le sens de lecture : le sélecteur cible l'élément hôte, pas ce qu'il contient. .card:has(> img) sélectionne la carte qui possède une image en enfant direct. Combiné aux pseudo-classes d'état, il permet de remonter l'information sans JavaScript : styler un label quand son champ est invalide, un formulaire quand un champ a le focus, une ligne de tableau quand sa case est cochée.

CSS
.field:has(input:invalid:not(:focus)) label {
  color: #dc2626;
}

.card:has(> img) {
  padding-top: 0;
}

tr:has(input[type="checkbox"]:checked) {
  background: #eef2ff;
}
Sélection selon le contenu ou l'état interne

Sur :nth-child(), deux acquis à consolider. D'abord la lecture des formules An+B : 2n (pairs), 2n+1 (impairs), -n+3 (les trois premiers), n+4 (du quatrième à la fin) ; l'intervalle « du 2e au 5e » s'écrit en combinant :nth-child(n+2):nth-child(-n+5). Ensuite la syntaxe of S, plus récente : :nth-child(2n of .visible) compte uniquement parmi les enfants qui matchent .visible, là où .visible:nth-child(2n) compte tous les enfants puis filtre - deux résultats très différents dès qu'il y a des éléments intercalés.

CSS
tr:nth-child(odd) {
  background: #fafafa;
}

li:nth-child(-n + 3) {
  font-weight: 600;
}

li:nth-child(n + 2):nth-child(-n + 5) {
  border-top: 1px solid #e5e7eb;
}

.row:nth-child(2n of .visible) {
  background: #eef2ff;
}
Formules An+B et syntaxe of S

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Ces styles par défaut doivent pouvoir être surchargés par la simple classe .link, malgré le #main présent dans la liste. Quelle pseudo-classe placer dans le trou ?
    ___(#main, .nav, a) {
      color: #6b7280;
    }
    
    .link {
      color: #2563eb;
    }
    • :where
    • :is
    • :not
    • :has
  2. Que sélectionne .card:has(> img) ?
    • Les images enfants directes d'une carte
    • Les cartes qui contiennent une image en enfant direct
    • Les cartes situées après une image dans le DOM
    • Toutes les images descendantes des cartes
  3. Dans une liste où seuls certains li portent .visible, que fait li:nth-child(2n of .visible) ?
    • Il cible les li pairs de la liste qui ont aussi la classe .visible
    • Il cible un li sur deux en ne comptant que les li.visible
    • Il cible les li pairs puis leur ajoute la classe .visible