CSS states & pseudo-classes

Did you know CSS on its own can already add a lot of dynamism to your HTML pages?

This article is also available on Medium.

When you work as a web developer and create a new web page, you’ll always end up relying on the same 3 programming languages:

  • HTML for the structure, the skeleton
  • JavaScript (JS) for the logic, the dynamics
  • CSS for the styles and visual customisation

Even if you use a framework like React, AngularJS or Vue.js, those tools are simply intermediaries that create files which will eventually get “compiled” (we actually say they’re “bundled”) into native HTML, JS and CSS so that the browser can interpret them.

But while new toolboxes and frameworks were created, those languages have also slowly become pretty powerful on their own, and using just barebones HTML or CSS can already give pretty amazing results! Sure, true page logic is done via JS, but you can get impressive animations and effects just with CSS

So, today, let’s discuss the various “states” your page elements can be in and how you can use CSS pseudo-classes to define styles for each!

States and pseudo-classes

At its core, an HTML page is just a deep tree of nodes. All those elements can be visible or hidden and together they describe the structure of your content. Using CSS then allows you to reference those various elements and customise how they appear on the user’s screen.

The thing is that elements are not necessarily static blocks anymore! With the evolution of web programming languages, we are now dealing with more complex entities that live and breath in your page and switch between different states depending on the user’s interactions and the overall browser context.

These states can be accessed and referenced in CSS too thanks to the “pseudo-classes”. Those are specific colon-prefixed (:) tags that you add to your CSS queries to specify you want to style an element when it’s in a given state.

In this article, I’ll focus on the three most commonly used pseudo-classes: :hover, :active and :focus. But for a full list of available pseudo-classes by category, you can check out the MDN reference!

The “normal” state

So far, you might have already read or written basic CSS queries to customise an HTML element in the page, like this:

Here, I’m simply setting all the <div>s in the page to use a bold font, and all the <li>s to use a light blue background. Nothing fancy – we’re just doing basic CSS. I could add some IDs and classes, but it would still be pretty simple… and static.

In that case, we’re defining styles for the “normal” (base) state of our elements: that CSS block tells the browser how to show the elements by default, when there is no particular interaction or context-related parametrisation.

The “hover” and “active” states: making a basic button

But now, let’s say you create a new button in your HTML page using the native <button> tag:

Then you’ll see that, by default, the browser has some built-in styles for when your mouse enters the area of the button or when you actually click on it. It clearly behaves differently from our <div>s and <li>s and makes use of some additional states!

The problem is that if you start to add some styling to your button, you’ll lose all the nice interactivity and user feedback:

That’s because your normal state is basically overriding and “fixing” the button’s properties… so, you don’t have any change in the background colour when your mouse gets on the button, or any “pointer” cursor, or a cool effect when you click the element.

Time to use some pseudo-classes to restore the “on mouse enter” and “on click” visual effects 🙂

The “on mouse enter” state is called hover; it’s defined using the :hover pseudo-class. The “on click” state is the active state, defined using the :active pseudo-class:

At that point, we’ve successfully added back the “hover” and “active” states to properly inform the user this element is clickable, but with our own custom styles!

We could even mix this notion of pseudo-classes with other sweet CSS concepts, like transitions, to get really cool effects:

Also, what’s really neat is that these :hover and :active pseudo-classes can actually be applied to virtually all element types in your layout, not just buttons! So you can add this kind of interactivity effects on a <div>, an <a> link, a <p> paragraph… or an image:

Important note: as explained in the MDN docs, the :hover state isn’t possible on touch-based devices such as tablets or mobiles; so you shouldn’t show valuable info in this intermediary state because you run the risk part of your audience will miss it! 😉

The “focus” state: styling an input

Another common pseudo-class is the “focus” state: this is the state your element gets if you’ve selected it and designated it as the current main element – for example, this happens a lot in forms with inputs:

See this blue border around the input whenever I click it to edit or check the text value? That’s the native styling the browser has for the “focus” state!

But you can use :focus along with other pseudo-classes to change this style and fully customise your input:

The <input> is kind of a peculiar tag that actually has a lot of pseudo-classes – so many it has its own dedicated category on MDN! This allows you to define styles for very specific states such as an invalid or a read-only input in a form, a required or optional text field, etc.

Context-sensitive and experimental pseudo-classes

As I mentioned before, there are some more “global” pseudo-classes that take into account not only the current element but also the context around it. A good example of that is the :visited pseudo-class for links – in addition to having info on the <a> element, it also looks at data at the browser level to know whether this specific user has already clicked on the link and seen the related page! (In its own way, even the :hover state has to know an “external” parameter: the position of the mouse!)

There are also some pseudo-classes that are still experimental, :playing or :paused, for playable medias such as videos. Keep in mind though that because they are experimental, they likely won’t work on all browsers/all device types and should therefore be avoided in production code!


Pseudo-classes are a powerful built-in feature of CSS that allows you to boost the interactivity, user-friendliness and dynamism of your web pages easily! Most can be applied to lots of element types and allow you to completely customise your styles while reproducing the browser’s native experience.

What about you: do you have any specific tips and tricks about CSS pseudo-classes? Feel free to share them in the comments and tell me if you have ideas of other web-dev tutorials I could make! 🙂

Leave a Reply

Your email address will not be published.