:is() (:matches(), :any())

Cette fonction est expérimentale
Puisque cette fonction est toujours en développement dans certains navigateurs, veuillez consulter le tableau de compatibilité pour les préfixes à utiliser selon les navigateurs.
Il convient de noter qu'une fonctionnalité expérimentale peut voir sa syntaxe ou son comportement modifié dans le futur en fonction des évolutions de la spécification.

La pseudo-classe :is() prend comme argument une liste de sélecteurs, et cible tous les éléments sélectionnés par chaque sélecteur de cette liste. Cela permet d'écrire des sélecteurs expansifs de façon plus concise.

La plupart des navigateurs prennent encore en charge cette fonctionnalité via :matches(), ou via la pseudo-classe préfixée — :any() (anciennes versions de Chrome, Firefox et Safari). :any() fonctionne exactement comme :matches() et :is() mais nécessite l'utilisation de préfixes et ne prend pas en charge les sélecteurs complexes.

Note : :matches() a été renommé en is() d'après l'issue 3258 du CSSWG.

/* Sélectionne n'importe quel paragraphe survolé 
   qui se trouve au sein d'un header, main, ou 
   footer */
:is(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

/* La notation précédente est équivalente à */
header p:hover,
main p:hover,
footer p:hover {
  color: red;
  cursor: pointer;
}


/* La version rétro-compatible avec :-*-any()  */
:-moz-any(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}
:-webkit-any(header, main, footer) p:hover{
  color: red;
  cursor: pointer;
}
:matches(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

Syntaxe

:is( <complex-selector-list> )


<complex-selector-list> = <complex-selector>#


<complex-selector> = <compound-selector> [ <combinator>? <compound-selector> ]*


<compound-selector> = [ <type-selector>? <subclass-selector>* [ <pseudo-element-selector> <pseudo-class-selector>* ]* ]!
<combinator> = '>' | '+' | '~' | [ '||' ]


<type-selector> = <wq-name> | <ns-prefix>? '*'
<subclass-selector> = <id-selector> | <class-selector> | <attribute-selector> | <pseudo-class-selector>
<pseudo-element-selector> = ':' <pseudo-class-selector>
<pseudo-class-selector> = ':' <ident-token> | ':' <function-token> <any-value> ')'


<wq-name> = <ns-prefix>? <ident-token>
<ns-prefix> = [ <ident-token> | '*' ]? |
<id-selector> = <hash-token>
<class-selector> = '.' <ident-token>
<attribute-selector> = '[' <wq-name> ']' | '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']'


<attr-matcher> = [ '~' | | | '^' | '$' | '*' ]? '='
<attr-modifier> = i | s

Exemples

Exemple fonctionnant pour les différents navigateurs

HTML

<header>
  <p>Voici un paragraphe dans un en-tête.</p>
</header>

<main>
  <ul>
    <li><p>Mon premier élément de</p><p>liste</p></li>
    <li><p>Mon deuxième élément de</p><p>liste</p></li>
  </ul>
</main>

<footer>
  <p>Et un paragraphe de pied de page</p>
</footer>

CSS

:-webkit-any(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

:-moz-any(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}
:is(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

JavaScript

let matchedItems;

try {
  matchedItems = document.querySelectorAll(':is(header, main, footer) p');
} catch(e) {
  try {
    matchedItems = document.querySelectorAll(':matches(header, main, footer) p');
  } catch(e) {
    try {
      matchedItems = document.querySelectorAll(':-webkit-any(header, main, footer) p');
    } catch(e) {
      try {
        matchedItems = document.querySelectorAll(':-moz-any(header, main, footer) p');
      } catch(e) {
        console.log('Votre navigateur ne prend pas en charge :is(), :matches() ou :any()');
      }
    }
  }
}

for(let i = 0; i < matchedItems.length; i++) {
  applyHandler(matchedItems[i]);
}

function applyHandler(elem) {
  elem.addEventListener('click', function(e) {
    alert('Ce paragraphe est à l\'intérieur d\'un élément ' + e.target.parentNode.nodeName);
  });
}

Simplifier les listes de sélecteurs

La pseudo-classe :matches() permet de simplifier largement les sélecteurs CSS. Ainsi, la règle suivante :

/* les listes non ordonnées sur 3 niveaux ou plus */
/* utilisent un carré comme puce */
ol ol ul,     ol ul ul,     ol menu ul,     ol dir ul,
ol ol menu,   ol ul menu,   ol menu menu,   ol dir menu,
ol ol dir,    ol ul dir,    ol menu dir,    ol dir dir,
ul ol ul,     ul ul ul,     ul menu ul,     ul dir ul,
ul ol menu,   ul ul menu,   ul menu menu,   ul dir menu,
ul ol dir,    ul ul dir,    ul menu dir,    ul dir dir,
menu ol ul,   menu ul ul,   menu menu ul,   menu dir ul,
menu ol menu, menu ul menu, menu menu menu, menu dir menu,
menu ol dir,  menu ul dir,  menu menu dir,  menu dir dir,
dir ol ul,    dir ul ul,    dir menu ul,    dir dir ul,
dir ol menu,  dir ul menu,  dir menu menu,  dir dir menu,
dir ol dir,   dir ul dir,   dir menu dir,   dir dir dir {
  list-style-type: square;
}

pourra être remplacée par :

/* les listes non ordonnées sur 3 niveaux ou plus */
/* utilisent un carré comme puce */
:matches(ol, ul, menu, dir) :matches(ol, ul, menu, dir) ul,
:matches(ol, ul, menu, dir) :matches(ol, ul, menu, dir) menu,
:matches(ol, ul, menu, dir) :matches(ol, ul, menu, dir) dir {
  list-style-type: square;
}

En revanche, le modèle d'usage suivant n'est pas recommandée (cf. la section qui suit sur les performances) :

:matches(ol, ul, menu, dir) :matches(ol, ul, menu, dir) :matches(ul, menu, dir) {
  list-style-type: square;
}

Simplifier les sélecteurs de section

La pseudo-classe :matches est particulièrement utile lorsqu'on manipule les sections et en-têtes HTML5. <section>, <article>, <aside> et <nav> étant souvent imbriqués les uns dans les autres, les mettre en forme (sans :matches()) s'avèrerait plutôt compliqué.

Par exemple, pour mettre en forme les éléments <h1> à différents niveaux sans utiliser :matches(), on obtient ces règles plutôt compliquées :

/* Niveau 0 */
h1 {
  font-size: 30px;
}
/* Niveau 1 */
section h1, article h1, aside h1, nav h1 {
  font-size: 25px;
}
/* Niveau 2 */
section section h1, section article h1, section aside h1, section nav h1,
article section h1, article article h1, article aside h1, article nav h1,
aside section h1, aside article h1, aside aside h1, aside nav h1,
nav section h1, nav article h1, nav aside h1, nav nav h1 {
  font-size: 20px;
}
/* Niveau 3 */
/* … j'ai abandonné */

Avec :is(), c'est plus simple :

/* Niveau 0 */
h1 {
  font-size: 30px;
}
/* Niveau 1 */
:is(section, article, aside, nav) h1 {
  font-size: 25px;
}
/* Niveau 2 */
:is(section, article, aside, nav)
:is(section, article, aside, nav) h1 {
  font-size: 20px;
}
/* Niveau 3 */
:is(section, article, aside, nav)
:is(section, article, aside, nav)
:is(section, article, aside, nav) h1 {
  font-size: 15px;
}

Éviter l'invalidation d'une liste de sélecteur

À la différence des listes de sélecteurs, la pseudo-classe :is() ne devient pas invalide lorsqu'un des sélecteurs passés en argument n'est pas pris en charge par le navigateur.

:is(:valid, :incompatible) {
  ...
}

Le sélecteur ci-dessus sera analysé sans problème et permettra de cibler :valid même si les navigateurs ne prennent pas en charge le sélecteur :incompatible. En revanche :

:valid, :incompatible {
  ...
}

L'exemple ci-dessus ne sera pas appliqué par les navigateurs qui ne prennent pas en charge :incompatible, même si :valid est bien pris en charge.

Notes

Problèmes de performances avec any(): et la spécificité

bug 561154 suit un problème de spécificité relatif à :-moz-any(). L'implémentation  place :-moz-any() dans la catégorie des règles universelles, ce qui signifie que si on l'utilise comme sélecteur le plus à droite, ce sera plus lent que d'utiliser un sélecteur d'identifiant, de classe ou de balise comme premier sélecteur.

Ainsi :

.a > :-moz-any(.b, .c)

sera plus lent que

.a > .b, .a > .c

et cette dernière version sera plus rapide :

:-moz-any(.a, .d) > .b, :-moz-any(.a, .d) > .c

:is() doit permettre de corriger de tels problèmes.

Spécifications

Spécification État Commentaires
Selectors Level 4
La définition de ':is()' dans cette spécification.
Version de travail Définition initiale.

Compatibilité des navigateurs

Update compatibility data on GitHub
OrdinateurMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariWebview AndroidChrome pour AndroidFirefox pour AndroidOpera pour AndroidSafari sur iOSSamsung Internet
:is()Chrome Support complet 68
Notes Désactivée
Support complet 68
Notes Désactivée
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Désactivée From version 68: this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled). To change preferences in Chrome, visit chrome://flags.
Aucun support 66 — 71
Notes Autre nom Désactivée
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Autre nom Cette fonctionnalité utilise le nom non-standard : :matches()
Désactivée From version 66 until version 71 (exclusive): this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled). To change preferences in Chrome, visit chrome://flags.
Support complet 12
Notes Autre nom
Notes Doesn't support combinators.
Autre nom Cette fonctionnalité utilise le nom non-standard : :-webkit-any()
Edge Aucun support NonFirefox Support complet 4
Notes Autre nom
Support complet 4
Notes Autre nom
Notes Doesn't support combinators.
Notes See bug 906353
Autre nom Cette fonctionnalité utilise le nom non-standard : :-moz-any()
IE Aucun support NonOpera Support complet 55
Notes Désactivée
Support complet 55
Notes Désactivée
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Désactivée From version 55: this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
Aucun support 53 — 58
Notes Autre nom Désactivée
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Autre nom Cette fonctionnalité utilise le nom non-standard : :matches()
Désactivée From version 53 until version 58 (exclusive): this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
Support complet Oui
Notes Autre nom
Notes Doesn't support combinators.
Autre nom Cette fonctionnalité utilise le nom non-standard : :-webkit-any()
Safari Support complet 9
Autre nom
Support complet 9
Autre nom
Autre nom Cette fonctionnalité utilise le nom non-standard : :matches()
Support complet 5
Notes Autre nom
Notes Doesn't support combinators.
Autre nom Cette fonctionnalité utilise le nom non-standard : :-webkit-any()
WebView Android Support complet ≤37
Notes Autre nom
Support complet ≤37
Notes Autre nom
Notes Doesn't support combinators.
Autre nom Cette fonctionnalité utilise le nom non-standard : :-webkit-any()
Chrome Android Aucun support 66 — 71
Notes Autre nom Désactivée
Aucun support 66 — 71
Notes Autre nom Désactivée
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Autre nom Cette fonctionnalité utilise le nom non-standard : :matches()
Désactivée From version 66 until version 71 (exclusive): this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled). To change preferences in Chrome, visit chrome://flags.
Support complet 18
Notes Autre nom
Notes Doesn't support combinators.
Autre nom Cette fonctionnalité utilise le nom non-standard : :-webkit-any()
Firefox Android Support complet 4
Notes Autre nom
Support complet 4
Notes Autre nom
Notes Doesn't support combinators.
Notes See bug 906353
Autre nom Cette fonctionnalité utilise le nom non-standard : :-moz-any()
Opera Android Support complet 48
Notes Désactivée
Support complet 48
Notes Désactivée
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Désactivée From version 48: this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
Aucun support 47 — 50
Notes Autre nom Désactivée
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Autre nom Cette fonctionnalité utilise le nom non-standard : :matches()
Désactivée From version 47 until version 50 (exclusive): this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
Support complet Oui
Notes Autre nom
Notes Doesn't support combinators.
Autre nom Cette fonctionnalité utilise le nom non-standard : :-webkit-any()
Safari iOS Support complet 9
Autre nom
Support complet 9
Autre nom
Autre nom Cette fonctionnalité utilise le nom non-standard : :matches()
Support complet 5
Notes Autre nom
Notes Doesn't support combinators.
Autre nom Cette fonctionnalité utilise le nom non-standard : :-webkit-any()
Samsung Internet Android Aucun support 9.0 — 10.0
Autre nom
Aucun support 9.0 — 10.0
Autre nom
Autre nom Cette fonctionnalité utilise le nom non-standard : :matches()
Support complet Oui
Autre nom
Autre nom Cette fonctionnalité utilise le nom non-standard : :-webkit-any()

Légende

Support complet  
Support complet
Aucun support  
Aucun support
Voir les notes d'implémentation.
Voir les notes d'implémentation.
Une action explicite de l'utilisateur est nécessaire pour activer cette fonctionnalité.
Une action explicite de l'utilisateur est nécessaire pour activer cette fonctionnalité.
Cette fonctionnalité utilise un nom non-standard.
Cette fonctionnalité utilise un nom non-standard.

Voir aussi