A closer look at the :where() and :is() functions in CSS
:where()
Functions accept a list of selectors as arguments, allowing you to write less code and style them at the same time. In this article, we will discuss :where()
pseudo-class functions and demonstrate how to use it in a production environment. We'll review :where()
overlays, priorities, and safety related to functions. We'll also look at some specific use cases and discuss its similarities and :is()
differences with functions.
1.What is :where() function?
According to MDN , :where()
is a CSS pseudo-class function selector that accepts a selector list as an argument and applies the given style to any element in the list, so it is useful for :where()
shortening a long selector list.
In CSS, when the same style rule is applied to multiple elements at the same time, we usually write a long list of selectors separated by commas.
Here's an example where we apply the same style to header
all tags within main
the element and the element :footer
<a>
header a:hover,
main a:hover,
footer a:hover {
color: green;
text-decoration: underline;
}
In the above code snippet, we have only selected three elements, but if there are a large number of elements and selectors, the code will start to look untidy and may become difficult to read and understand. This is :where()
where pseudo-class functions come into play.
Here's what the above example would look like using :where()
the function:
:where(header, main, footer) a:hover {
color: red;
text-decoration: underline;
}
When the browser reaches this code snippet, the code instructs the browser to find the header
, main
and footer
selectors and locate all a
tags within these selectors. Then, when the user hovers over any of these a
tags, the browser should apply the specified styles, in this case red and underline. This pseudo-class function allows us to write a long list of selectors in a shorter and easier to understand way.
2. Combination, division and superposition: where() function
Using :where()
functions, we can group elements in many ways and combinations. We can :where()
place the function at the beginning, middle or end of the selector. Here's an example with multiple selectors and styles:
/* first list */
header a:hover,
main a:hover,
footer a:hover {
color: green;
text-decoration: underline;
}
/* second list */
article header > p,
article footer > p{
color: gray;
}
/* third list */
.dark-theme button,
.dark-theme a,
.dim-theme button,
.dim-theme a{
color: purple;
}
Here's the same code, :where()
rewritten using a function:
/* first list */
/* at the beginning */
:where(header, main, footer) a:hover {
color: red;
text-decoration: underline;
}
/* second list */
/* in the middle */
article :where(header, footer) > p {
color: gray;
}
/* third list */
/* at the end */
.dark-theme :where(button, a) {
color: purple;
}
.dim-theme :where(button, a) {
color: purple;
}
In the first list, we specify that the red and underlineheader
styles should be applied to the , main
element and the element on hover footer
. In the second list, we specify that article
the , header
and footer
elements should be styled in gray .
For greater clarity, we split the third list into two :where()
functions. In this list, we specify that the style of the and elements in .dark-theme
, . should be purple .dim-theme
button
a
Now we will further reduce the third list function, turning them into a :where()
function:
/* stacked */
:where(.dark-theme, .dim-theme) :where(button, a) {
color: purple;
}
This strategy for reducing complex selector lists is called stacking.
3. :where() selector priority
:where()
Function selectors always have priority zero. Therefore, any element targeted by this function also automatically gets a priority of 0. This allows us to easily unstyle any element.
Here is an example of an HTML ordered list:
<div>
<h2>First list no class</h2>
<ol>
<li>List Item 1</li>
<li>List Item 2</li>
</ol>
</div>
<div>
<h2>Second list with class</h2>
<ol class="second-list">
<li>List Item 1</li>
<li>List Item 2</li>
</ol>
</div>
<div>
<h2>Third list with class</h2>
<ol class="third-list">
<li>List Item 1</li>
<li>List Item 2</li>
</ol>
</div>
In the above code snippet, there are three ordered lists with two items in each list. The second and third lists have a given class, while the first list does not.
Without any styling, we can see that each list is in numerical order:
Now, let's add some styling:
:where(ol[class]) {
list-style-type: none;
}
In the above code snippet, we use :where()
the pseudo-class function to select all tags to which the class is applied ol
.
Below, we see the second and third lists, both of which have a class :where()
targeted by the function, with their removed list-style-type
:
Now, let's add some extra styling:
:where(ol[class]) {
list-style-type: none;
}
.second-list {
list-style-type: disc;
}
Just for the second list using the class name, we can see that it now appears as bullets, while the third list still has no list style type:
You might be thinking, "Shouldn't this be the case, since the new styles are written under the :where()
function styles?" No, it's not, as we'll see in a moment.
:where()
Let's see what happens when we move the code we just added to the top of the code block, and the functions section to the bottom:
.second-list {
list-style-type: disc;
}
:where(ol[class]) {
list-style-type: none;
}
Notice that the style still hasn't changed:
Remember, :where()
functions have priority zero.
4. Safety of :where() selector
For selector lists, if the browser does not recognize one selector in the list, the entire list of selectors will be considered invalid and their styles will not be applied. However, :where()
this is not the case for pseudo-class functions.
If :where()
an element in a function is the target of an invalid selector, the element will not get any styles. The remaining elements will still be styled. :where()
The function will skip invalid selectors to the next (valid) selector. That's why :where()
it's called a safe selector.
In the example below, :unsupported
this is an invalid selector for many browsers. The code below will be parsed correctly and will still match :valid
selectors, even in :unsupported
browsers that don't support selectors, like this:
:where(:valid, :unsupported) {
...
}
However, in browsers that do not support :unsupported
selectors, the following code will be ignored, even if they support :valid
selectors:
:valid, :unsupported {
...
}
5. Special use cases of :where() function
There are some special use cases where :where()
a function can be a useful tool, but there are also situations where its use should be avoided. Almost all problems that arise when using :where()
pseudo-class functions come down to priorities. Because :where()
has zero priority, we need to choose very carefully when and where to use this function.
First, let's look at a few use cases where this :where()
might be particularly useful.
5.1 Improve CSS reset
A CSS reset is when a set of style rules is loaded before any other styles to clear the browser's built-in styles. CSS resets are usually placed at the top or beginning of CSS stylesheets, so they load first. Developers often use them to remove the default styles that browsers give to a few elements initially, before starting to actually design their elements and websites. CSS reset can also help eliminate inconsistencies between different browsers.
CSS resets are temporary styles that are changed later during the styling process. However, depending on the simplicity or complexity of the selector for the element or group of elements used in the CSS reset, it may be difficult to override the initial style later in the code.
For example, let's say we set all a
tags on our website to green . Then, we later decided to style all header
of a
the tags in to gray .
Due to the complexity of the selection in CSS reset, the new (gray) style will not be applied. The selector in the reset has a higher priority than the selector used in the code behind only for header
the <in> tag, so no gray style is applied.a
Now, if we :where()
add the pseudo-class function to CSS reset, this will automatically give zero priority to all elements in the reset. This makes it easier for us to change the style later without having to worry about priority conflicts.
5.2 Delete styles
:where()
Functions are useful if you want to remove or cancel a style or lower the priority of an element or group of elements .
5.3 Keep style
If you want to ensure that the style or priority of an element or set of elements will not change at any time in the future, then do not use :where()
pseudo-classes.
6. What is the :is() function?
:is()
Functions behave almost :where()
the same as functions. You can use it to simplify complex selectors, or you can place it at the beginning, middle, or end of a selector, just like a :where()
function.
It's also safe, just like :where()
functions. So when one of the selectors is invalid, the browser ignores that selector, but the valid selector's styles are added to the selected element.
7. The difference between :where() and :is() functions
The difference between these two functions is that :where()
the priority of a function is always zero, whereas :is()
the priority of a function is determined by the priority of its most specific argument. For example, let's look at header
paragraph text within the element:
<header>
<p>This is a paragraph text.</p>
</header>
Then, let's try using four different selectors to change the text color:
header p {
color: blue;
}
:is(header, section) p {
color: green;
}
p {
color: blue;
}
:where(header, section) p {
color: blue;
}
The first selector sets the color of the text to blue. :is()
The second selector using has the same priority as the first selector, but since it is after the first selector, it changes the text color from blue to green . The third selector has lower priority than the first and second selectors and has no effect on the text. Finally there is the fourth one, which uses :where()
the function which has no effect on the text because of its zero precedence.
8. Browser Compatibility
All browsers, whether desktop or mobile, have full support for CSS :where()
functions, including support for their security features. Therefore, you don't have to worry about whether your styles will render correctly in the browser.