---
title: "CSS Pseudo-Classes: The Must-Have, the Unusual, and the Experimental | CoderPad"
description: "Pseudo-classes are CSS features that allow us to do pretty amazing things when it comes to stylizing our content. Pseudo-classes come in handy, and not many developers know about them. This article teaches the must-have, the unusual, and the experimental pseudo-classes."
canonical: "https://coderpad.io/blog/development/css-pseudo-classes/"
last_modified: "2023-06-05 14:16:52"
---
[Back to blog](https://coderpad.io/blog/)

# CSS Pseudo-Classes: The Must-Have, the Unusual, and the Experimental

August 16, 2022 9 Minute Read

By Tom Quinonero

[Development](https://coderpad.io/blog/development/)

Pseudo-classes are CSS features that allow us to do pretty amazing things when it comes to stylizing our content.

Some common uses are applying styles to:

- Mouse/keyboard interactions (ex:`:hover`,`:active`,`:focus`),
- Fields based on their content (ex:`:blank`,`:valid`,`:checked`) or
- Elements based on their position in the DOM (ex:`:first-child`,`:nth-child()`,`:root`).

Pseudo-classes themselves are keywords that we add after our selector.

>

🗒️ That syntax might remind you of pseudo-elements like`::before`and`::selection`. Pseudo-classes and pseudo-elements are different things. Pseudo-classes target states of an element like hover, disabled, or visited. Pseudo-elements affect elements that aren’t explicitly written to the DOM, like a before element, a backdrop, or the selection. This post will focus on pseudo-classes only.

In this post, we’ll deep dive into pseudo-classes: the must-have, the unusual, and even the brand-new experimental ones!

## Learn how to run front-end developer interviews that don’t suck

[Read our guide](https://coderpad.io/blog/interviewing/5-tips-for-interviewing-frontend/)

## Relative Selectors

Relative selectors are any pseudo-class used to select an element based on its position on the DOM.

First, we have`:first-child`and`:last-child`. As their name suggests, they are used to select an element’s first or last child.

On top of that, you can use`:nth-child`whenever you need to select the n th element.

Here is an example:

```
/* Make the first li red */
li:first-child{
  color:red;
}

/* Make the 3rd li blue */
li:nth-child(3){
  color : blue
}Code language: CSS (css)
```

Another example of a relative selector I use all the time for styling tables is the`:nth-child(even)`selector that selects even elements.

There is also the standard trick of setting a margin-bottom to some elements and making it`0px`on the`:last-child`.

>

💡 For more information, read the [MDN documentation for relative selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes#tree-structural_pseudo-classes), referred to as Tree structural pseudo-classes.

## User Interaction Selector

A user interaction selector is any selector responding to user input like a mouse click, a hover, or an element focused on with the keyboard.

In CSS development, we use these a lot, so let’s dive into them!

### Link status pseudo-classes

First, let’s talk about the links. You can use the`:visited`pseudo-class to target any link that a user visited:

```
a:visited{
  color: #c58af9;
}Code language: CSS (css)
```

That is the purple color you see on the Google results you’ve already visited:

[](https://coderpad.io/wp-content/uploads/2022/08/img_62f154c58605c.png) Results from Google. The link you already visited appears in purple instead of blue, stylized using the`:visited`pseudo-class.

You can also target non-visited links by using the`:link`pseudo-class.

In great news for CSS developers, another fascinating pseudo-class has recently been released — [`:any-link`](https://developer.mozilla.org/en-US/docs/Web/CSS/:any-link). It combines`:visited`and`:link`, and it targets all links (and [`area`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area)) with a valid`href`attribute.

There’s also [`:local-link`](https://developer.mozilla.org/en-US/docs/Web/CSS/:local-link), the recently developed but not-yet-supported pseudo-class that targets links of the same domain you’re currently on.

With these pseudo-classes, you can have a different style for a link pointing to an external domain than for the link pointing to the current website. If the`href`target is the same as the document URL, it will match.

### Hover, Focus, and Active

To target an element hovered over by the mouse, use the`:hover`pseudo-class. We use this for links, buttons, and other elements that will be clickable.

Here is how you make a link go red on hover:

```
a:hover{
  color: red;
}Code language: CSS (css)
```

>

![⚠️](https://coderpad.io/assets/emoji/26a0.svg) In reality, you can use`:hover`on any element you want, but be careful. If not done sparingly, it will confuse your users and create a bad experience for them.

`:focus`is often used to target a field the user clicked or tabbed into. It’s super useful for form fields and buttons.

By default, the browser uses an`outline`on`:focus`, and of course you can overwrite this. That is how you edit the default outline:

```
a:focus{
  outline: 2px dashed blue;
}Code language: CSS (css)
```

>

![⚠️](https://coderpad.io/assets/emoji/26a0.svg) Before you remove an outline on focus, remember that the browser uses an outline for accessibility concerns: keyboard users should be able to clearly identify what’s being focused on (aka what will be triggered when pressing`Enter`). More information on this matter can be found in the focus indicator section of [Introduction to Web Accessibility](https://coderpad.io/blog/development/introduction-to-web-accessibility-a11y/#focus-indicators) by [Corbin Crutchley](https://twitter.com/crutchcorn).

`:active`is used when a click is being made or held. I always use this to make the button “pop” on a click. It provides excellent visual feedback to the user, so they know the website acknowledged their click.

I usually make a small`transform: translateY(2px);`when`:active`for my buttons — but you can get more creative, like the way [Material UI Buttons](https://mui.com/material-ui/react-button/) react on clicks:

### Focus-visible and Focus-within

By default, when the user clicks on something with their mouse, it activates the`:focus`styling, even if you want to show that styling only for the keyboard. We may not want that behavior when focusing with the mouse simply because it does not look good, but we need it when using the keyboard for accessibility reasons.

With the help of`:focus-visible`, you can style an element only when the user is focused with their keyboard. It will target elements that need to show focus, so it will target our element only if`:focus`is using`tab`.

So when focusing on an element, the browser would determine if it matched`:focus-visible`, based on the input method used.

>

💡 Check out the example below and [the MDN documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) for more information on`:focus-visible`.

Now let’s talk about`:focus-within`. This powerful selector allows us to select an element based on its children’s focus state. Focus-within enables you to target a form that has a focus element within.

Let’s say you want the focus of an input to make the field container look focused instead of the input itself. You can disable the focus on the field and use`:focus-within`on the field container to make it look how you want it to.

Take a look at the example below that demonstrates both Focus-visible and Focus-within. If you focus on the email field, you’ll notice that the error message appears. Also, the focus is on the whole field, not just the input.

Try clicking the different buttons. You’ll see that the ones using focus-visible don’t show any outline:

### The`:target`selector

Did you know that instead of carrying you to another page, a link can target an element of the current page instead?

If you use the`#`symbol and the element ID as an`href`attribute for your link, clicking it will make the user “jump” to the new element. In HTML, we call that an anchor.

Anchors were always powerful and became even more so since the introduction of smooth-scrolling and`scroll-padding-top`. You can now make with native CSS what would have been quite a pain to do in JavaScript a few years ago.

The`:target`pseudo-class expands what you can do with anchors by letting us stylize the targeted element.

For our example below, you have a few paragraphs and a summary. By using`:target`, you can add an outline to the current paragraph:

>

💡 If you wonder how deep you can go with anchor links and the target pseudo-class, look at [Kevin Powell recreating the Netflix carousel with only CSS](https://www.youtube.com/watch?v=b--q6Fsf_cA).

## Styling Form Fields

Many pseudo-classes are available for us to make our form fields look significantly better.

In this section, you’ll look at disabled, required, optional, valid, and invalid pseudo-classes.

### Disabled

A disabled element cannot be interacted with — usually, this will be an input, a select, or a button. To disable an element, use the disabled attribute on our element in HTML.

Visually, we show it by graying it out, making it evident that the element cannot be interacted with.

### Required & Optional

In HTML, use the`required`attribute on an input to indicate its need to be filled before submitting the form. You can then use the`:required`pseudo-class to target those elements and put an emphasis on them.

CSS also provides the`:optional`pseudo-class to target the inputs that are not required.

### Valid & Invalid

When dealing with fields in HTML, you can specify what types of data are acceptable and what types are not. Using a [REGEX expression](https://coderpad.io/blog/development/the-complete-guide-to-regular-expressions-regex/), you can ask for numbers, an email address, or even a custom pattern.

In CSS, inputs have a`valid`or`invalid`state that you can stylize using the`:valid`and`:invalid`selectors.

Usually, we display a red outline on`invalid`fields to clearly show the user which fields are blocking their form submission.

### Example

The example below is a form using all the form-related pseudo-classes we just mentioned.

- The name field is`required`and is currently empty, so it’s`invalid`and has a red outline.
- The address is not required, so it is`valid`and has a green border even though it’s empty.
- The company is`disabled`, so its opacity is lower, and the cursor is set to`not-allowed`.
- The email field is invalid as the value contains two`@`symbols. It is`invalid`and is stylized with a red border.

And as you can see, the form itself can be stylized with`:valid`and`:invalid`too. A form needs all its fields to be`valid`to be`valid`itself:

## New Pseudo-Classes

All the pseudo-classes mentioned in this post, except for`:focus-within`and`:focus-visible`, were available in the ecosystem for quite some time.

But in this section, we’ll talk about new and exciting stuff.

### The`:not`selector

The`:not`pseudo-class is pretty much self-explanatory. It allows us to declare what we do NOT want in our selector. It makes life much easier sometimes to exclude elements from our selector instead of including all the ones we want.

The`:not`pseudo-class allows us to write a cleaner and more descriptive selector.

Let’s say you want to target every link that is not a button. You can now write it in a much simpler way:

```
/* without using :not */
a {
  color: brown;
}
.button {
  color: white;
}

/* using :not */
a:not(.button) {
  color: brown;
}Code language: CSS (css)
```

It doesn’t look like a lot, but when using the`:not`selector, you don’t even need to know the button’s color.

>

💡 Modern browsers have supported`:not`since 2020, look at the [caniuse page](https://caniuse.com/css-not-sel-list) for more information.

### The`:where`&`:is`pseudo-classes

The`:is`selector allows us to write [DRYer](https://blog.boot.dev/clean-code/dry-code/#:~:text=What%20is%20DRY%20Code%3F,data%20normalization%20to%20avoid%20redundancy.) code by consolidating multiple selectors. Let’s say you need to target buttons from`.header`,`.footer`and`.sidebar`.

Without the`:is`selector, you might write something like this:

```
.header .button,
.footer.button,
.sidebar .button {
  background: teal;
}Code language: CSS (css)
```

This feels like unnecessary repetition, doesn’t it?

Using`:is`you can write:

```
:is(.header, .foooter, .sidebar) .button {
  background: teal;
}Code language: CSS (css)
```

This code is shorter, easier to read, and [supported in major web browsers](https://caniuse.com/css-matches-pseudo).

To understand`:where`, we need to talk about selector specificity.

First, if you are unfamiliar with specificity, read this great [deep dive from Smashing Magazine](https://www.smashingmagazine.com/2007/07/css-specificity-things-you-should-know/).

Also, to try your selector specificity, I recommend [this great tool](https://polypane.app/css-specificity-calculator/) from Polypane.

When working with large CSS codebases, specificity is always a struggle. When defining defaults, we need the specificity to be as low as possible.

The`:where`pseudo-class acts like`:is`, but it always has a 0 specificity, when`:is`specificity will be the most specific in its selector list.

It makes the`:where`super helpful in writing base styles that can easily be overwritten.

>

💡 I recommend [this post](https://css-tricks.com/using-the-specificity-of-where-as-a-css-reset/) by [Mojtaba Seyedi](https://twitter.com/mojtabaseyedi) going through an actual use case of the`where`pseudo-class in the context of a CSS reset.

### All about`:has`, a promising but experimental selector

The`:has`selector allows you to select an element based on its children. You can, for example, use it for selecting any field container with an`:invalid`input inside.

Unfortunately, as of this writing, the`:has`pseudo-class is not yet supported in major browsers.

[](https://coderpad.io/wp-content/uploads/2022/08/img_62f154c71127d.png) [The `:has` pseudo-class on caniuse](https://caniuse.com/css-has). Currently only supported on Safari and the latest version of Chrome.

Still, we are getting there, and this is exciting progress for CSS developers.

>

💡 If you want to read more about`:has`, I recommend [Ibadehin Mojeed](https://twitter.com/ibaslogic/) ’s article on it, [How and when to use the CSS`:has`selector](https://blog.logrocket.com/how-when-use-css-has-selector/). Also, check the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/:has) for it.

I’m Tom Quinonero, I write about design systems and CSS. [Follow me on Twitter](https://twitter.com/tomquinonero) for more tips and resources 🤙

Sources and Links:

- [The CSS Specificity Calculator](https://www.notion.so/Pseudo-Classes-in-CSS-206043e785db437493aa9204bf5cab5f)
- [CSS Specificity: Things You Should Know](https://www.smashingmagazine.com/2007/07/css-specificity-things-you-should-know/) by [Vitaly Friedman](https://twitter.com/vitalyf)
- [Using the Specificity of :where() as a CSS Reset](https://css-tricks.com/using-the-specificity-of-where-as-a-css-reset/) by [Mojtaba Seyedi](https://www.notion.so/Pseudo-Classes-in-CSS-206043e785db437493aa9204bf5cab5f)
- [A Guide To Newly Supported, Modern CSS Pseudo-Class Selectors](https://www.smashingmagazine.com/2021/04/guide-supported-modern-css-pseudo-class-selectors/) by [Stephanie Eckels](https://twitter.com/5t3ph/)
- [How and when to use the CSS :has selector](https://blog.logrocket.com/how-when-use-css-has-selector/) by [Ibadehin Mojeed](https://twitter.com/ibaslogic/)

## Subscribe for more CoderPad insights

## Trending Articles

Previous slide Next slide [Development

## What is Prompt Engineering?

Introducing AI tools such as ChatGPT and Bard helps increase the efficiency of tasks such as data generation, code generation and completion, text summarization, etc. How were these AI tools trained to answer almost every question you ask them? The answer, prompt engineering, is discussed in this blog post.

Read the post](https://coderpad.io/blog/development/what-is-prompt-engineering/) [Development

## A Guide To Using React’s useCallback() Hook

Are you looking to optimize your React applications? Have you heard of the useCallback hook? useCallback is a powerful React hook that helps you optimize your application by preventing unnecessary re-renders. In this post, we'll dive into React's useCallback() hook, define referential equality and callback functions and how to tie it all together.

Read the post](https://coderpad.io/blog/development/a-guide-to-using-reacts-usecallback-hook/) [Development

## MySQL vs. PostgreSQL: How Do They Compare?

A database is a convenient tool that allows users to access information, maintain records, and apply commonly used operations, such as insertion, modification, deletion, and data organization. Learn about MySQL vs PostgreSQL, their features, advantages, and disadvantages. Finally, check out which one is the best choice for you.

Read the post](https://coderpad.io/blog/development/mysql-vs-postgresql-how-do-they-compare/) [Development

## PostgreSQL LIKE Operator: A Detailed Guide

When using databases, searching for values that match a given pattern is a familiar necessity. Learn how you can retrieve entries with queries including a particular string using Postgres LIKE operator.

Read the post](https://coderpad.io/blog/development/postgresql-like-operator-a-detailed-guide/) [Development

## How To Use DataProvider In TestNG With Examples

When it comes to testing there are many tools and techniques available. In this post, we'll discuss how to use DataProvider with TestNG.

Read the post](https://coderpad.io/blog/development/how-to-use-dataprovider-in-testng-with-examples/) [Development

## How To Get Up And Running With Django Migrations: A Guide

Django migrations are a way of handling the application of changes to a database schema. By following the steps outlined in this guide, you can easily set up and use migrations in your Django projects.

Read the post](https://coderpad.io/blog/development/how-to-get-up-and-running-with-django-migrations-a-guide/) [Development

## Writing A Parameterized Test In JUnit With Examples

A JUnit parameterized test allows you to decouple data from structure, generating cleaner and more reliable tests. Learn more in this guide.

Read the post](https://coderpad.io/blog/development/writing-a-parameterized-test-in-junit-with-examples/) [Development

## How To Use Assert In JUnit With Examples

The JUnit Assert class is what you use to write unit testing assertions in JUnit. Learn more about it in this guide, full of examples.

Read the post](https://coderpad.io/blog/development/how-to-use-assert-in-junit-with-examples/) [Development

## A Simple Guide To TypeORM: What It Is And How To Use It

Considering current languages have object-oriented programming features, most database management systems are based on the relational model, with tables instead of objects. For these reasons, mapping relational objects is very important in development. In this article, you will learn what TypeORM, one of the main tools used today, is.

Read the post](https://coderpad.io/blog/development/a-simple-guide-to-typeorm-what-it-is-and-how-to-use-it/) [Development

## Using PreparedStatement in JDBC With Examples

In this post, we'll see why and how to work with JDBC and PreparedStatement. We will also learn along with examples using code.

Read the post](https://coderpad.io/blog/development/using-preparedstatement-in-jdbc-with-examples/) [Development

## React vs React Native: The Differences Explained

React and React Native are similar in that they both allow web developers to build applications based on the unique concept of components. But the two frameworks do this in radically different ways. In this post, we cover the key differences between react and react native frameworks, implementation, and which is an appropriate choice.

Read the post](https://coderpad.io/blog/development/react-vs-react-native-the-differences-explained/) [Development

## Logging in Django

The most challenging part of fixing a problem is identifying it. Unfortunately, this statement is exceptionally true when it comes to debugging. Learn how to use the power of logging into your Django applications to improve your debug process in this article.

Read the post](https://coderpad.io/blog/development/logging-in-django/)

## Hire with confidence.

See why engineering teams trust CoderPad to evaluate developers with realistic, AI-ready hiring workflows.

[Request a demo](https://coderpad.io/sales/)
