{"id":263984,"date":"2017-12-21T09:02:59","date_gmt":"2017-12-21T16:02:59","guid":{"rendered":"http:\/\/css-tricks.com\/?page_id=263984"},"modified":"2022-12-02T09:58:31","modified_gmt":"2022-12-02T17:58:31","slug":"is","status":"publish","type":"page","link":"https:\/\/css-tricks.com\/almanac\/selectors\/i\/is\/","title":{"rendered":":is"},"content":{"rendered":"\n
The pseudo-select We could write:<\/p>\n\n\n\n This can make quick work of otherwise extremely verbose, complex, and error prone selectors. See:<\/p>\n\n\n\n You can attach the pseudo-selector to an element like you’d expect. Like to select a specific type of element when it has either of two classes:<\/p>\n\n\n\n Simplifying selectors with But beware! Preprocessors, like Sass, “unroll” your nested rules into a list of easily-understood selectors. According to the CSS4 Working Draft<\/a>:<\/p>\n\n\n\n The specificity of the :is() pseudo-class is replaced by the specificity of its most specific argument. Thus, a selector written with :is() does not necessarily have equivalent specificity to the equivalent selector written without :is().<\/p><\/blockquote>\n\n\n\n That means that the specificity of Normally if any part of a selector is invalid, the entire block is thrown out:<\/p>\n\n\n\n I’ve heard browsers might chill out on this in the future, but we aren’t there yet. If you are hoping to keep that and not have to break it into two separate blocks, I always think about This browser support data is from Caniuse<\/a>, which has more detail. A number indicates that browser supports the feature at that version and up.<\/p><\/div>:is()<\/code> in CSS allows you to write compound selectors more tersely. For example, rather than writing:<\/p>\n\n\n\n
ul li,\nol li {}<\/code><\/pre>\n\n\n\n
:is(ul, ol) li {}<\/code><\/pre>\n\n\n\n\n\n\n\n
:is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6) {\n color: #BADA55;\n}\n\n\/* ... which would be the equivalent of: *\/\nsection h1, section h2, section h3, section h4, section h5, section h6, \narticle h1, article h2, article h3, article h4, article h5, article h6, \naside h1, aside h2, aside h3, aside h4, aside h5, aside h6, \nnav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {\n color: #BADA55;\n}<\/code><\/pre>\n\n\n\n
div:is(.cool, .fun) {\n color: red;\n}\n\n\/*\n<div class=\"cool\">match<\/div>\n<div class=\"fun\">match<\/div>\n<p class=\"fun\">not match<\/p>\n*\/<\/code><\/pre>\n\n\n
Hey, isn’t that like CSS preprocessing?<\/h3>\n\n\n
:is()<\/code> is similar to how CSS preprocessors handle nested rules:<\/p>\n\n\n\n
\/* SCSS written like this: *\/\ndiv, p, ul, ol {\n span {\n \/* ... *\/\n }\n}\n\n\/* after processing becomes: *\/\ndiv span, p span, ul span, ol span {\n \/* ...*\/\n}\n\n\/* which is a lot like the effect of :is()! *\/<\/code><\/pre>\n\n\n\n
:is()<\/code> will handle specificity rules a little differently.<\/p>\n\n\n
Specificity of
:is()<\/code><\/h3>\n\n\n
:is()<\/code> gets auto-upgraded<\/em> to the most specific item in the list of arguments provided:<\/p>\n\n\n\n
\/* This has higher precedence... *\/\n:is(ol, .list, ul) li { \/* ... *\/ }\n\n\/* ...than this, even though this is later... *\/\nol li { \/* ... *\/ }\n\n\/* ...because :is() has the weight of it's heaviest selector, which is `.list`! *\/<\/code><\/pre>\n\n\n
Forgiving selector lists<\/h3>\n\n\n
p, p::not-real {\n color: red; \/* nothing will be red, as ::not-real is an invalid selector *\/\n}<\/code><\/pre>\n\n\n\n
is()<\/code> can help because it’s “forgiving”:<\/p>\n\n\n\n
:is(p, p::not-real) { \/* this is fine *\/\n color: red;\n}<\/code><\/pre>\n\n\n\n
::selection<\/code> and the
::-moz-selection<\/code> vendor prefix version when I think of invalid comma-separated selectors, but…<\/p>\n\n\n\n
:is(::selection, ::-moz-selection) { \/* this doesn't work in Chrome for some reason 🤷♀️ *\/\n background: yellow;\n}<\/code><\/pre>\n\n\n
Browser support<\/h3>\n\n
Desktop<\/h4>