:is(), :where(), :has() and :not() in CSS

Published On:
Read Time: 4 mins

CSS comes with set of selectors that can be used to target specific DOM elements and styles them however we want. but some times it gets bit difficult to target specific element(s) becuase of the complex strucutre of the DOM but now worries, Pseudo-classes have got our backs! So today let's have a look at them today and try to understand how we can use them just to make our lives bit easier :).


:has()

You might have guessed just by its name. :has() is used when we want to styles an element if its passes some condition, we pass that condition to the has. Here the condition can be a selector itself. Let's take a look at the examples below to understand it more clearly.

/* form that has an input that is focused */
form:has(input:focus) {
  border: 2px solid teal;
}

In above example, we are adding a border to a form if one of its inputs is in focus state. In cases like this :has() can be very useful.

Note: At the time of writing this :has() is not fully supported on the web, so do check out if its supported here.

:not()

The :not() is kind of opposite to :has(). It is used to select elements that do not match a specified selector. It simply excludes certain elements from being styled by a CSS rule. It is known as the negation pseudo-class. Let's see an example below.

/* highlight the text */
p.highlight {
  color: crimson;
  font-weight: 700;
}

/* don't highlight the text */
p:not(.highlight) {
  color: gray;
  font-weight: 500;
}

In above example, it won't will apply styles to a <p> based on the highlight class. Check the browser support here.

:is()

The :is() allows to group multiple selectors together and apply a the styles to elements that match any of those selectors. It is basically used to simplify the process of applying the same styles to multiple selectors, and helps in making the CSS code more concise, redable and maintainable.

/* without :is() */
div button:hover,
div p:hover,
div strong:hover {
  color: hotpink;
}

/* with :is() */
div :is(button, p, strong):hover {
  color: hotpink;
}

In above example, we can clearly say that the styles written using :is() are more easier to read and understand. Its important to note that pseudo-elements are not valid in the selector list for :is(). Check the browser support here.

:where()

The :where() is identical (funcitonally) to :is(). It takes a list of selectors as an argument and applies the styles to those elements. Just like the :is() it makes the selector list shorter and hence it makes CSS code more concise and maintainable. The difference between :where() and :is() is that :where() always has zero specificity and :is() has the specificity of the most specific selector in its arguments list. The use cases of :where() can be removing the deafult stylings of the elements or minifying the CSS code just to make it more maintainable and redable.

/* without :where() */
main h1,
main h2,
main h3,
main p {
  font-family: "Inter", sans-serif;
}

/* with :where() */
main :where(h1, h2, h3, p) {
  font-family: "Inter", sans-serif;
}

In above example, we're adding the font-family to some elements and using :where() to make our code more redable and shorter. Check the browser support here.

Combining multiple pseudo class functions

We can even combine these pseudo class functions and get most out of them. Here is an example of it.

/* Select blog with the keyword "CSS" in the heading */
.blog:has(h2:contains("CSS")) {
  color: royalblue;
}

/* Exclude articles with the keyword "CSS" in the heading */
.blog:not(:has(h2:contains("CSS"))) {
  color: hotpink;
}

Here, let's assume that we are styling the heading of a blog, and if the article is contains the word CSS means its related to CSS we'll change its color to blue or to hotpink othewise.

That's a wrap, Hope you enjoyed and learnt a thing or two, stay stuned!


Built with Nextjs, Tailwindcss and much