:matches() (:any())

The :matches() CSS pseudo-class function takes a selector list as its argument, and selects any element that can be selected by one of the selectors in that list. This is useful for writing large selectors in a more compact form.

Note that many browsers support this functionality through an older, prefixed pseudo-class — :any(), including older versions of Chrome, Firefox and Safari. This works in exactly the same way as :matches(), except that it requires vendor prefixes and doesn't support complex selectors.

/* Selects any paragraph inside a header, main
   or footer element that is being hovered */
:matches(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() */
:-moz-any(header, main, footer) p:hover,
:-webkit-any(header, main, footer) p:hover,
:matches(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

Syntax

:matches( <selector># )

Examples

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>
:matches(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

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

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

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 :matches() or :any()');
    }
  }
}

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

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

Simplifying list selectors

The :matches() pseudo-class can greatly simplify your CSS selectors. For example, the following 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;
}

... can be replaced with:

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

However, do not use the following: (See the section on performance below.)

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

Simplifying section selectors

The :matches pseudo-class is particularly useful when dealing with HTML5 sections and headings. Since <section>, <article>, <aside>, and <nav> are commonly nested together, without :matches(), styling them to match one another can be tricky.

For example, without :matches(), styling all the <h1> elements at different depths could be very complicated:

/* 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! */

Using :matches(), though, it's much easier:

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

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

:matches() aims to fix such problems.

Specifications

Specification Status Comment
Selectors Level 4
The definition of ':matches()' in that specification.
Working Draft Initial definition

Browser compatibility

Update compatibility data on GitHub
DesktopMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidEdge MobileFirefox for AndroidOpera for AndroidiOS SafariSamsung Internet
Basic supportChrome Full support 66
Full support 66
Full support 12
Alternate Name
Alternate Name Uses the non-standard name: :-webkit-any
Edge Full support 15
Full support 15
Full support 12
Alternate Name
Alternate Name Uses the non-standard name: :-ms-matches
Firefox Full support 4
Alternate Name
Full support 4
Alternate Name
Alternate Name Uses the non-standard name: :-moz-any
IE No support NoOpera Full support Yes
Alternate Name
Full support Yes
Alternate Name
Alternate Name Uses the non-standard name: :-webkit-any
Safari Full support 9
Full support 9
Full support 5
Alternate Name
Alternate Name Uses the non-standard name: :-webkit-any
WebView Android Full support 66
Full support 66
Full support Yes
Alternate Name
Alternate Name Uses the non-standard name: :-webkit-any
Chrome Android Full support 66
Full support 66
Full support 18
Alternate Name
Alternate Name Uses the non-standard name: :-webkit-any
Edge Mobile No support NoFirefox Android Full support 4
Alternate Name
Full support 4
Alternate Name
Alternate Name Uses the non-standard name: :-moz-any
Opera Android Full support Yes
Alternate Name
Full support Yes
Alternate Name
Alternate Name Uses the non-standard name: :-webkit-any
Safari iOS Full support 9
Full support 9
Full support 5
Alternate Name
Alternate Name Uses the non-standard name: :-webkit-any
Samsung Internet Android No support No

Legend

Full support  
Full support
No support  
No support
Uses a non-standard name.
Uses a non-standard name.

See also

Document Tags and Contributors

Contributors to this page: ExE-Boss, chrisdavidmills, Sheppy, schalkneethling
Last updated by: ExE-Boss,