Pseudo-classe CSSPseudo-classes

:has()

Sélectionne un élément en fonction de ce qu’il contient ou de ce qui se trouve après lui. Permet de styliser un parent selon ses enfants.

Sur cette page

Exemple

#
CSS
.card {
  display: grid;
  gap: 10px;
}

.card:has(img) {
  grid-template-columns: 56px 1fr;
  align-items: center;
}
Aperçu

Définition et utilisation

#

La pseudo-classe :has() vérifie si quelque chose correspondant au sélecteur donné existe à l’intérieur de l’élément ou à côté de lui. .card:has(img) sélectionne les cartes qui contiennent une image, et form:has(:invalid) les formulaires avec au moins un champ incorrect. Pendant des années, ce « sélecteur de parent » passait pour impossible en CSS.

Le sélecteur entre parenthèses est relatif à l’élément. Sans combinateur, il désigne un descendant à n’importe quelle profondeur ; avec >, seulement un enfant direct (ul:has(> li.active)) ; et avec + ou ~, un frère placé plus loin : h2:has(+ p) désigne un titre suivi d’un paragraphe. :has() offre ainsi aussi un sélecteur de frère précédent.

La condition s’applique en direct. label:has(input:checked) changera l’apparence de l’étiquette au moment où le champ est coché, et body:has(dialog[open]) peut bloquer le défilement de la page quand une fenêtre est ouverte. De nombreuses tâches qui nécessitaient du JavaScript se règlent en une seule règle.

La spécificité se calcule comme dans :is() : c’est le poids du sélecteur le plus fort de la liste. :has() ne peut contenir ni un autre :has() ni de pseudo-éléments. Restreignez-le à des composants précis, car le navigateur doit souvent recalculer des règles trop larges.

Syntaxe

#
Syntaxe
:has( <liste de sélecteurs relative> )

Exemples de sélecteurs

#
  • .card:has(img)

    Les cartes qui contiennent une image. La carte avec seulement du texte reste grise.
  • .card:has(input:checked)

    Cochez la case de la troisième carte : toute la carte se met en valeur, pas seulement la case.
  • .card:not(:has(img))

    Condition inversée : les cartes sans image.
  • .demo:has(input:checked)

    Le conteneur réagit à l’état d’un champ situé à l’intérieur. Cochez la case et observez la bordure.

Exemples de sélecteurs en pratique

#

.card:has(img)

Les cartes qui contiennent une image. La carte avec seulement du texte reste grise.
.card:has(img) { background: #7c3aed; color: #fff; }

.card:has(input:checked)

Cochez la case de la troisième carte : toute la carte se met en valeur, pas seulement la case.
.card:has(input:checked) { background: #7c3aed; color: #fff; }

.card:not(:has(img))

Condition inversée : les cartes sans image.
.card:not(:has(img)) { background: #7c3aed; color: #fff; }

.demo:has(input:checked)

Le conteneur réagit à l’état d’un champ situé à l’intérieur. Cochez la case et observez la bordure.
.demo:has(input:checked) {
  border-color: #a78bfa;
  background: rgb(124 58 237 / 0.15);
}

Plus d’exemples

#
Champ de formulaire avec une erreur
CSS
.field:has(input:invalid) {
  border-color: #f43f5e;
}

.field:has(input:invalid) .error {
  display: block;
}
Aperçu

Saisissez un texte sans le signe @. La bordure et le message changent au niveau de tout le champ, bien que l’erreur ne concerne que le champ de saisie.

Compatibilité des navigateurs

#

Largement disponible · depuis 2023

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

  • Chrome
  • Edge
  • Firefox
  • Safari

Bonnes pratiques

#
  • Restreignez :has() à un composant, par exemple .card:has(img). Un :has(…) isolé, sans rien avant les deux-points, vérifie chaque élément de la page.
  • Les navigateurs plus anciens ignoreront entièrement une règle contenant :has(). Prévoyez une apparence correcte sans elle, et traitez :has() comme une amélioration, par exemple dans un bloc @supports selector(:has(a)).
  • Avant d’ajouter une classe au parent en JavaScript, vérifiez si :has() associé à une pseudo-classe d’état, comme :checked, :focus-visible ou :invalid, ne suffit pas déjà.

Entrées associées

#

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