Le sélecteur CSS :has() : révolutionnez votre ciblage et simplifiez votre code
Découvrez comment le sélecteur CSS :has() révolutionne votre ciblage et simplifie votre code. Exemples concrets, cas pratiques et compatibilité 2026.
Si vous aviez à désigner une seule fonctionnalité CSS qui a véritablement changé la donne ces dernières années, :has() serait probablement en tête de liste. Surnommé pendant longtemps le « sélecteur parent » — un terme qui résume à lui seul toute la frustration des développeurs front-end —, :has() offre enfin la possibilité de cibler un élément selon ce qu’il renferme dans son contenu, ce qui revenait autrefois à demander à JavaScript de faire le travail sale à la place du CSS. En 2026, avec un support natif qui dépasse allègrement les 93 % des navigateurs actuels d’après Can I Use, il n’y a plus vraiment d’excuse pour ne pas l’adopter dans vos projets au quotidien.

Comprendre le sélecteur CSS :has() et ce qui le rend si particulier
:has() est une pseudo-classe fonctionnelle CSS qui s’applique à un élément dès lors qu’au moins un de ses descendants correspond au sélecteur qu’on lui passe en paramètre. Dit autrement : il vous permet de « remonter » dans l’arbre DOM directement depuis CSS — ce qu’aucune pseudo-classe n’avait rendu possible jusqu’ici. C’est exactement là que réside toute sa singularité.
La syntaxe, pas si compliquée
/* Cible un <article> qui contient au moins une <img> */
article:has(img) {
border: 2px solid #0070f3;
}
/* Cible un <label> dont l'input associé est coché */
label:has(input:checked) {
font-weight: bold;
color: green;
}
/* Cible un <section> qui contient un <h2> suivi d'un <p> */
section:has(h2 + p) {
padding-block: 2rem;
}
Avant :has(), ces trois scénarios auraient nécessité du JavaScript ou des classes ajoutées manuellement (souvent côté serveur, souvent pénible à maintenir). La spécification CSS Selectors Level 4, formalisée par le W3C, a officiellement intégré cette pseudo-classe au standard depuis 2023 — ce qui lui donne une légitimité solide.
Pourquoi tout le monde parle de « sélecteur parent » ?
L’expression vient du fait que :has() permet de styler un élément en réaction à ce que ses enfants font ou sont. C’est l’exact inverse du paradigme CSS classique, qui ne permettait de descendre dans l’arbre DOM, jamais d’y remonter. Cette inversion de logique — même si techniquement on cible toujours le parent, pas l’enfant — est précisément ce qui a fait de :has() le Graal du CSS pendant des années.

Support navigateur en 2026 : le feu vert pour la production
Oui, sans hésitation — :has() est taillé pour la production en 2026. Le support global s’établit à 93,4 % selon les statistiques de Can I Use au premier trimestre 2026. C’est largement suffisant pour l’utiliser sans complexe sur la majorité des projets.
Ce que disent les chiffres
| Navigateur | Version minimale | Support |
|---|---|---|
| Chrome / Edge | 105+ | ✅ Complet |
| Safari / iOS | 16.0+ | ✅ Complet |
| Firefox | 121+ | ✅ Complet |
| Samsung Internet | 20+ | ✅ Complet |
| Opera | 91+ | ✅ Complet |
| IE 11 | — | ❌ Non supporté |
Firefox a été le dernier grand navigateur à franchir le pas, avec sa version 121 publiée en décembre 2023. Depuis, les trois moteurs de rendu majeurs — Blink, WebKit et Gecko — reconnaissent nativement :has(). Internet Explorer, lui, reste dans sa tombe numérique habituelle.
Gérer les navigateurs récalcitrants
Pour les rares situations où d’anciens navigateurs entrent en jeu, la directive @supports est votre meilleure alliée :
@supports selector(:has(img)) {
article:has(img) {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
Cette stratégie de progressive enhancement garantit que votre mise en page de base reste fonctionnelle partout, et que l’amélioration conditionnelle ne s’active que là où le navigateur est capable de la comprendre. C’est exactement la même philosophie qui gouverne les Container Queries 2026 : Révolutionnez votre Responsive Design, une autre avancée CSS moderne qui transforme en profondeur la conception d’interfaces adaptatives.
5 exemples concrets pour exploiter :has() au maximum
La vraie question c’est : dans quels cas pratiques :has() va-t-il vraiment vous faire gagner du temps ? Voici cinq situations réelles, directement applicables.
1. Réagir à l’état d’un formulaire sans une ligne de JS
/* Le formulaire se colore en rouge si un input est invalide */
form:has(input:invalid) {
outline: 2px solid crimson;
}
/* Le bouton submit devient cliquable si tout est valide */
form:has(input:valid):not(:has(input:invalid)) button[type="submit"] {
opacity: 1;
pointer-events: auto;
}
Cette règle remplace à elle seule des dizaines de lignes d’événements JavaScript. Le navigateur n’a plus à gérer des event listeners sur chaque champ — le rendu est plus fluide, point.
2. Adapter l’apparence d’une carte selon son contenu
/* Une card avec image adopte un layout en grille */
.card:has(img) {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1.5rem;
}
/* Une card sans image reste en colonne simple */
.card:not(:has(img)) {
display: flex;
flex-direction: column;
}
Terminées les classes .card--with-image ou .card--text-only à jongler côté serveur. Le CSS s’ajuste tout seul à la réalité du HTML, sans intermédiaire.
3. Un header sticky seulement quand c’est utile
/* Le header reste fixe seulement si la page contient un article suffisamment long */
header:has(~ main article:has(> p:nth-child(10))) {
position: sticky;
top: 0;
z-index: 100;
}
4. Un dark mode 100 % CSS grâce à une checkbox
body:has(#dark-mode-toggle:checked) {
--bg: #0f0f0f;
--text: #f0f0f0;
color-scheme: dark;
}
Une seule règle, et vous avez un mode sombre sans JavaScript. La checkbox peut rester invisible visuellement, son label stylisé comme un bouton toggle. C’est propre, performant, accessible. Difficile de faire plus élégant.
5. Alertes visuelles dans un dashboard
/* Le widget devient rouge en présence d'une alerte critique */
.dashboard-widget:has(.alert--critical) {
border-color: var(--color-danger);
background: color-mix(in srgb, var(--color-danger) 10%, white);
}

:has() face à JavaScript : lequel choisir, et quand ?
:has() s’impose dans beaucoup de situations — mais pas dans toutes. Voici une comparaison honnête, sans chercher à couronner un vainqueur absolu.
Ce que dit le tableau
| Critère | CSS :has() | JavaScript |
|---|---|---|
| Performance de rendu | ✅ Natif, optimisé par le moteur | ⚠️ Event listeners coûteux |
| Réactivité aux changements DOM | ✅ Automatique | ⚠️ Nécessite des observers |
| Logique conditionnelle complexe | ⚠️ Limitée | ✅ Illimitée |
| Accessibilité | ✅ Aucune interaction JS nécessaire | ⚠️ Risque si mal géré |
| Animations avancées | ✅ Transitions CSS natives | ✅ Via Web Animations API |
| Prise en charge des données | ❌ Ne lit pas les données | ✅ Accès complet |
| Debug et outillage | ✅ DevTools CSS | ✅ Console, breakpoints |
La règle de base est assez simple, au fond : si la condition est purement visuelle et ancrée dans la structure HTML, :has() est le bon outil. Si vous devez interroger une API, manipuler des données ou gérer une logique métier — JavaScript reste irremplaçable, et personne ne prétend le contraire.
Ce que ça change concrètement pour les performances
Des benchmarks réalisés par l’équipe Chrome DevRel en 2024 montrent que remplacer des toggles de classList par des sélecteurs CSS natifs réduit le temps de mise en page (layout time) de 15 à 40 % selon la complexité des composants. Ces gains se reflètent directement sur les métriques Core Web Vitals — notamment le Cumulative Layout Shift (CLS) et l’Interaction to Next Paint (INP), qui sont justement ceux que Google surveille de près pour le référencement.
Combinaisons avancées : :has() avec :not() et :is()
La véritable puissance de :has() éclate quand on commence à le combiner avec d’autres pseudo-classes modernes. C’est là que ça devient vraiment intéressant.
:has() + :not() : pour exclure avec précision
/* Cible les sections sans aucun titre */
section:not(:has(h2, h3, h4)) {
border-left: 4px solid orange;
}
:has() + :is() : grouper proprement
/* Cible tout conteneur renfermant un média interactif */
:is(article, section, aside):has(video, iframe, canvas) {
contain: layout;
aspect-ratio: 16 / 9;
}
:has() avec des relations entre frères
/* Cible le <ul> qui précède directement un bouton "voir plus" */
ul:has(+ button.load-more) {
margin-bottom: 0;
}
/* Cible un <h1> dont le frère suivant est un paragraphe de description */
h1:has(+ p.description) {
margin-bottom: 0.25rem;
}
Ces exemples révèlent quelque chose d’important : :has() ne se limite pas aux relations parent-enfant. Il gère aussi les relations entre éléments frères adjacents, ce qui multiplie encore les possibilités de ciblage précis — sans jamais toucher au HTML.
Spécificité et performances : les points à surveiller
:has() hérite de la spécificité la plus haute parmi ses arguments. Concrètement, div:has(.active) combine la spécificité d’une classe (0,1,0) et celle d’un élément (0,0,1), soit 0,1,1 — rien d’exceptionnel, c’est le comportement CSS standard.
Évitez les sélecteurs trop vagues dans :has()
/* À éviter : trop générique, peut peser sur les performances */
div:has(*) { ... }
/* À privilégier : un sélecteur précis et ciblé */
div:has(> .item:last-child) { ... }
Les moteurs de rendu modernes optimisent :has() de manière assez agressive depuis 2024 — mais garder le principe de sélectivité minimale en tête reste une bonne habitude, quelle que soit la fonctionnalité utilisée.

:has() dans le paysage CSS de 2026
:has() ne vit pas en vase clos — il s’inscrit dans un écosystème CSS qui évolue à toute vitesse. Associé aux Container Queries, aux cascade layers et aux custom properties, il forme une combinaison redoutable pour construire des systèmes de design entièrement déclaratifs, sans dépendance excessive à JavaScript.
Ce que font les frameworks avec :has()
Tailwind CSS 4.x (sorti en 2025) a intégré des variantes directement basées sur :has() dans ses classes utilitaires. On peut désormais écrire has-[img]:grid pour appliquer display: grid de façon conditionnelle — sans quitter l’écosystème utilitaire d’un centimètre.
Du côté des frameworks JavaScript, React, Vue et Svelte profitent eux aussi de :has() au niveau des CSS Modules ou des Scoped Styles, réduisant sensiblement le besoin de logique de classe conditionnelle dans les composants. Une tendance qui rejoint la réflexion plus large sur l’évolution du web, notamment celle explorée dans notre article sur les Progressive Web Apps (PWA) en 2026 : le futur des applications web natives ?.
:has() et la génération automatique de contenu
L’essor des générateurs de sites statiques et des outils d’IA pour la création web — un sujet qu’on aborde dans notre article sur comment l’IA générative transforme la création de contenu web en 2026 — bénéficie directement de :has(). Ces outils génèrent un HTML sémantique que :has() peut cibler sans qu’on ait besoin de bourrer le code de classes supplémentaires. Moins de couplage entre structure et présentation, c’est toujours une victoire.
Pour aller plus loin
- La spécification officielle CSS Selectors Level 4 du W3C décrit en détail le comportement de
:has(), avec toutes les subtilités formelles. - Le blog de Chrome for Developers propose des exemples interactifs et des explications sur l’implémentation dans Blink — très utile pour comprendre ce qui se passe sous le capot.
- MDN Web Docs propose une référence complète et constamment mise à jour de la pseudo-classe, avec des tableaux de compatibilité en temps réel.
Ce qu’on peut en retenir
En 2026, :has() tient toutes ses promesses. Il transforme réellement la façon de cibler les éléments, allège considérablement le code et réduit la dépendance à JavaScript pour tout ce qui relève de la logique purement visuelle. Avec un support navigateur qui dépasse les 93 %, il est pleinement opérationnel pour la production sur l’immense majorité des projets web actuels. Et quand on commence à le combiner avec :not(), :is() ou les sélecteurs de frères, on dispose d’un outil d’une précision remarquable pour construire des interfaces réactives, performantes et faciles à maintenir sur la durée.
Vous souhaitez intégrer :has() et les dernières avancées CSS dans votre prochain projet ? Contactez Webster Studio pour en discuter et bénéficier d’une expertise front-end ancrée dans les standards de 2026.