A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element.
You might already be familiar with the ones that are commonly used, such as :hover
.
In this post, we are going to explore some lesser-known and infrequently-used pseudo-classes and their practical use cases.
:is()
This function takes a list of selectors as its argument and selects any element that matches one of the selectors in that list.
Now, what we write like this:
article > h1, article > h2, article > h3 { color: #555; } button:focus, button:hover { border: 1px solid orangered; }
will become this:
article > :is(h1,h2,h3) { color: #555; } button:is(:focus, :hover) { border: 1px solid orangered; }
As you can see, this is useful for compactly writing large selectors.
Certain older versions of browsers support this functionality as :matches()
because:is
was previously called:matches()
.
We can also use the older, vendor-prefixed pseudo-class — :any()
— which acts in a similar way as :is()
.
article > :-webkit-any(h1,h2,h3) { color: #555; } article > :-moz-any(h1,h2,h3) { color: #555; } article > :matches(h1,h2,h3) { color: #555; }
:focus-within
This represents an element that has received focus or contains an element that has received focus.
<form> <label for="name">Name:</label> <input type="text" id="name"> <label for="email">Email</label> <input type="email" id="email"> </form>
We can modify the form styles when any of its input elements are focused.
form:focus-within { background: coral; }
Here’s a CSS-only dropdown made possible with :focus-within
(https://codepen.io/ananyaneogi/pen/KKwbyQX)
:focus-visible
It applies while an element is in the focused state.
Most browsers show a focus ring by default in this case.
This selector is useful for providing a different focus indicator based on how the user is interacting with the element (i.e with a mouse, a keyboard, etc.)
In this example, when we navigate the links with a keyboard (i.e. by tabbing), only then will the focus styles be applied.
This helps appy prominent styles to guide users who are navigating with a keyboard without altering focus states when using a mouse.
:focus-visible
No Description
:only-child
and :only-of-type
:only-child
selects an element that is the ONLY child of a parent. That means only one element exists within that parent. Even if it’s a different element type, it won’t be considered an only child. One element, no exceptions!
p:only-child { color: magenta; } <article> <p>A simple paragraph</p> <!-- p will be of magenta colour --> </article> <!-- ❌ no element selected because p is not the only child --> <article> <h1>Heading</h1> <p>A simple paragraph</p> </article>
:only-of-type
selects an element that is the ONLY child of a particular type within a parent. Having other siblings of different types is fine.
p:only-of-type { color: magenta;
}
<!-- p will be of magenta colour, because even though article contains more than one child but still <p> is the only one of it's own type --> <article> <h1>Heading</h1> <p>A simple paragraph</p> </article>
Here’s a practical example using :only-child
, adding a “Hurry, last item remaining” type of message to a product card if it’s the only product card remaining.
:only-child
No Description
:not()
This represents elements that do not match a list of selectors it takes as the argument.
<article> <p>A simple paragraph</p> <span>Span text</span> </article> /* Everything except the <p> inside the <article> will be of magenta colour! */ article :not(p) { color: magenta; }
This is not a very practical example but we can use :not()
along with other pseudo-classes to achieve interesting results. We’re going to see that next.
Note: nesting of :not
i.e :not(:not(...))
is invalid.
:empty
This represents any element that has no children. Children can be either element nodes or text including whitespace.
/* Selects any <span> that contains no content */ span:empty { background: magenta; }
Here’s an example of eliminating empty tags that contain no content using :empty
along with :not()
.
Target empty elements with :empty
No Description
:placeholder-shown
This represents any input element that is currently displaying the placeholder text.
In this example, we are highlighting the required fields in the form that are yet not filled by the user.
We are signaling that the fields are not yet filled in by simply targeting the inputs whose placeholder is still showing.
:required + :placeholder-shown – Highlight required fields
No Description
If you look closely in the example above, you’ll notice that another pseudo-class, :required,
is used along with :placeholder-shown
.
:required
is one of the many pseudo-classes related to forms that we have at our disposal. Next, we are going to look at some form-related pseudo-classes that make our form’s user experience better.
:required
This represents any input element that has the required attribute set on it. It is useful for highlighting fields that must be entered by the user before the form can be submitted.
:read-only
This represents an element that is not editable by the user.
:invalid</code
This represents any input form element whose contents fail to validate.
:valid
This represents any input form element whose contents validate successfully.
Here’s an example using the previously mentioned form-related pseudo-classes:
HTML Forms + CSS pseudo class
No Description
Remember to always refer to the browser compatibility before using them in production.
However, don’t let the browser inconsistency stop you from experimenting with new things: just keep a fallback handy and you’re good to go.
Find more documentation related to these pseudo-classes on MDN.
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowDing! You got a notification, but does it cause a little bump of dopamine or a slow drag of cortisol? […]
A guide for using JWT authentication to prevent basic security issues while understanding the shortcomings of JWTs.
Auth.js makes adding authentication to web apps easier and more secure. Let’s discuss why you should use it in your projects.
Compare Auth.js and Lucia Auth for Next.js authentication, exploring their features, session management differences, and design paradigms.