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

Esta é uma tecnologia experimental
Verifique a tabela de compatibilidade entre Navegadores cuidadosamente antes de usar essa funcionalidade em produção.

Nota: :matches() foi renomeado para :is() em CSSWG issue #3258.

A função pseudo-classe CSS :is() usa uma lista de seletores como argumento e seleciona qualquer elemento que possa ser selecionado por um dos seletores dessa lista. Isso é útil para escrever seletores grandes em uma forma mais compacta.

Note que atualmente os navegadores suportam essa funcionalidade como :matches(), ou através de uma pseudo-classe pré-fixada mais antiga — :any(), incluindo versões mais antigas do Chrome, Firefox, e Safari. :any() funciona exatamente da mesma maneira que :matches()/:is(), exceto que requer prefixos de fornecedor (vendor) e não suporta seletores complexos.

/* Selects any paragraph inside a header, main
   or footer element that is being hovered */
:is(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

/* The above is equivalent to the following */
header p:hover,
main p:hover,
footer p:hover {
  color: red;
  cursor: pointer;
}

/* Backwards-compatible version with :-*-any() and :matches()
   (It is not possible to group selectors into single rule,
   because presence of invalid selector would invalidate whole rule.) */
:-webkit-any(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}
:-moz-any(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}
:matches(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

Syntax

:is( <complex-selector-list> )

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

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

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

where
<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> ')'

where
<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>? ']'

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

Exemplos

Cross-browser example

<header>
  <p>This is my header paragraph</p>
</header>

<main>
  <ul>
    <li><p>This is my first</p><p>list item</p></li>
    <li><p>This is my second</p><p>list item</p></li>
  </ul>
</main>

<footer>
  <p>This is my footer paragraph</p>
</footer>
:-webkit-any(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

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

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

:is(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}
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('Your browser doesn\'t support :is(), :matches(), or :any()');
      }
    }
  }
}

matchedItems.forEach(applyHandler);

function applyHandler(elem) {
  elem.addEventListener('click', function(e) {
    alert('This paragraph is inside a ' + e.target.parentNode.nodeName);
  });
}

Simplificando a lista de seletores

A pseudo-classe :is() pode simplificar bastante seus seletores de CSS. Por exemplo, o seguinte CSS:

/* 3-deep (or more) unordered lists use a square */
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;
}

... pode ser substituído por:

/* 3-deep (or more) unordered lists use a square */
:is(ol, ul, menu, dir) :is(ol, ul, menu, dir) ul,
:is(ol, ul, menu, dir) :is(ol, ul, menu, dir) menu,
:is(ol, ul, menu, dir) :is(ol, ul, menu, dir) dir {
  list-style-type: square;
}

No entanto, não use o seguinte: (Consulte a seção sobre desempenho abaixo.)

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

Simplifying section selectors

A pseudo-classe :is() é particularmente útil ao lidar com seções e cabeçalhos em HTML5. Como <section>, <article>, <aside>, e <nav> são geralmente aninhados, sem :is(), estilizá-los para combinar um com outro pode ser complicado.

Por exemplo, sem :is(), estilizar todos os elementos <h1> em diferentes profundidades pode ser muito complicado:

/* Level 0 */
h1 {
  font-size: 30px;
}
/* Level 1 */
section h1, article h1, aside h1, nav h1 {
  font-size: 25px;
}
/* Level 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;
}
/* Level 3 */
/* ... don't even think about it! */

Usando :is(), porém, é muito mais fácil.

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

Evitando invalidação da lista de seletores

Diferentemente das listas de seletores, a pseudo-classe :is() não é invalidada quando um dos seletores passados para ela não é suportado pelo navegador.

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

Ainda analisará corretamente e corresponderá :valid mesmo em navegadores que não suportam :unsupported, enquanto:

:valid, :unsupported {
  ...
}

Será ignorado em navegadores que não suportam,:unsupported mesmo que eles suportem:valid

Notes

any(): — Issues with performance and specificity

bug 561154 tracks an issue with Gecko where the specificity of :-moz-any() is incorrect. The current (as of Firefox 12) implementation puts :-moz-any() in the category of universal rules, meaning using it as the rightmost selector will be slower than using an ID, class, or tag as the rightmost selector.

For example:

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

... is slower than:

.a > .b, .a > .c

... and the following is fast:

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

:is() aims to fix such problems.

Specifications

Specification Status Comment
Selectors Level 4
The definition of ':is()' in that specification.
Rascunho atual Initial definition

Browser compatibility

Update compatibility data on GitHub
DesktopMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung Internet
:is()Chrome Full support 68
Notes Disabled
Full support 68
Notes Disabled
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Disabled 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.
No support 66 — 71
Notes Alternate Name Disabled
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Alternate Name Uses the non-standard name: :matches()
Disabled 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.
Full support 12
Notes Alternate Name
Notes Doesn't support combinators.
Alternate Name Uses the non-standard name: :-webkit-any()
Edge No support NoFirefox Full support 4
Notes Alternate Name
Full support 4
Notes Alternate Name
Notes Doesn't support combinators.
Notes See bug 906353
Alternate Name Uses the non-standard name: :-moz-any()
IE No support NoOpera Full support 55
Notes Disabled
Full support 55
Notes Disabled
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Disabled From version 55: this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
No support 53 — 58
Notes Alternate Name Disabled
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Alternate Name Uses the non-standard name: :matches()
Disabled From version 53 until version 58 (exclusive): this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
Full support Yes
Notes Alternate Name
Notes Doesn't support combinators.
Alternate Name Uses the non-standard name: :-webkit-any()
Safari Full support 9
Alternate Name
Full support 9
Alternate Name
Alternate Name Uses the non-standard name: :matches()
Full support 5
Notes Alternate Name
Notes Doesn't support combinators.
Alternate Name Uses the non-standard name: :-webkit-any()
WebView Android Full support 66
Notes Alternate Name Disabled
Full support 66
Notes Alternate Name Disabled
Notes Has issues with combinators (see bug 842157).
Alternate Name Uses the non-standard name: :matches()
Disabled From version 66: this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
Full support ≤37
Notes Alternate Name
Notes Doesn't support combinators.
Alternate Name Uses the non-standard name: :-webkit-any()
Chrome Android No support 66 — 71
Notes Alternate Name Disabled
No support 66 — 71
Notes Alternate Name Disabled
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Alternate Name Uses the non-standard name: :matches()
Disabled 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.
Full support 18
Notes Alternate Name
Notes Doesn't support combinators.
Alternate Name Uses the non-standard name: :-webkit-any()
Firefox Android Full support 4
Notes Alternate Name
Full support 4
Notes Alternate Name
Notes Doesn't support combinators.
Notes See bug 906353
Alternate Name Uses the non-standard name: :-moz-any()
Opera Android Full support 48
Notes Disabled
Full support 48
Notes Disabled
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Disabled From version 48: this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
No support 47 — 50
Notes Alternate Name Disabled
Notes Combinators in the selector list argument may not match correctly (see bug 842157).
Alternate Name Uses the non-standard name: :matches()
Disabled From version 47 until version 50 (exclusive): this feature is behind the Experimental Web Platform Features preference (needs to be set to enabled).
Full support Yes
Notes Alternate Name
Notes Doesn't support combinators.
Alternate Name Uses the non-standard name: :-webkit-any()
Safari iOS Full support 9
Alternate Name
Full support 9
Alternate Name
Alternate Name Uses the non-standard name: :matches()
Full support 5
Notes Alternate Name
Notes Doesn't support combinators.
Alternate Name Uses the non-standard name: :-webkit-any()
Samsung Internet Android No support No

Legend

Full support  
Full support
No support  
No support
See implementation notes.
See implementation notes.
User must explicitly enable this feature.
User must explicitly enable this feature.
Uses a non-standard name.
Uses a non-standard name.

See also