When do the :hover, :focus, and :active pseudo-classes apply?
When we select an element by its .class
or #id
, we’re using predefined and unchanging attributes that are baked into the DOM. With pseudo-classes, we can select elements using information that isn’t already in the DOM and can change based on how a user interacts with the page.
:hover
, :focus
, and :active
are pseudo-classes that are determined by a user’s actions. They each correspond to a very specific point in how a user will interact with an element on a page such as a link or a button or an input field.
With the range in input devices we have today, these pseudo-classes also behave slightly differently depending on if the user is interacting with the element with a mouse 🐭, keyboard ⌨️, or touchscreen 📱, which can make it difficult to know how and when to style these situations.
When :hover
is applied #
The :hover
pseudo-class, also called the “pointer hover pseudo-class”, applies when a pointing device interacts with an element without necessarily activating it.
A typical example of this is when a mouse 🐭 hovers over an element. If you hover your mouse over the button below, you’ll see that it turns yellow.
button:hover { background-color: #ffdb3a; }
When on a mobile device 📱, there’s basically only one interaction you can take with any interactive element, which is tapping/clicking it. You may notice that if you tap on the button above, it also changes the colour despite the fact that you aren’t “just” hovering over it. This is because, on mobile devices, the events that trigger these pseudo-classes can become conflated. We’ll see with :focus
and :active
pseudo-classes as well.
Finally, for users of keyboard devices ⌨️, the :hover
pseudo-class is never triggered. The keyboard is not considered a “pointer” device and so can’t apply to this pointer hover pseudo-class.
When :focus
is applied #
The :focus
pseudo-class applies when an element is in a state that is ready to be interacted with, i.e. it has the focus of the input device. When this applies differs quite greatly between the different input devices.
When using a mouse 🐭 or similar pointing device, the :focus
pseudo-class will apply once the user has begun activating the element and, importantly, it will continue to stay in focus until the user activates another element. For example, if you click the button below with a mouse, you’ll notice that it turns yellow once you begin the click interaction. The button will only return to its default state if you click somewhere else on the page.
button:focus { background-color: #ffdb3a; }
For keyboard users ⌨️, focusing on an element is very similar to hovering over it for mouse users. I like to think of the :focus
pseudo-class as a hover state for keyboard devices, because it signals a similar intention for interaction.
For touchscreen users 📱, the :focus
pseudo-class applies, again, when the user taps on the element. However, it should be noted that this doesn’t apply for the mobile Safari browser.
When :active
is applied #
Finally, the :active
pseudo-class applies during the period in which the element is being activated. For example, if using a mouse 🐭, it would be the time between when the mouse button is clicked and when it is released.
If you click the button below quickly, you may not notice the brief change in colour, but if you press and maintain, you’ll see when the pseudo-class is applied.
button:active { background-color: #ffdb3a; }
The :active
pseudo-class works in the same way for mouse and keyboard ⌨️ interactions.
On mobile devices 📱, like the :focus
pseudo-class, the :active
pseudo-class applies on the tap of the element. And again, it doesn’t apply at all in the mobile Safari browser.
Combining :hover
, :focus
, and :active
#
One thing you may have noticed is that the conditions in which each of these pseudo-classes can be applied are not mutually exclusive. In fact, most times when an element is being clicked with a mouse, all three conditions are valid - the mouse if over the element, the element is in focus, and the element is being activated.
We can test this by only changing the background of the button if all three conditions apply.
button:hover:focus:active {
background-color: #ffdb3a;
}
If you click and hold the button below, you’ll see that it turns yellow. But if you click and hold while dragging your mouse away from hovering over it, you’ll see that it loses the colour.
This ability to combine the pseudo-classes can be really helpful for fine-tuning how we want to style the different states.
Order of styles - :hover
then :focus
then :active
#
Due to the fact that these conditions can and frequently are applied at the same time, the order in which we add these styles is important.
Let’s say we have the following styles:
button:active {
background-color: green;
}
button:focus {
background-color: blue;
}
button:hover {
background-color: red;
}
Only the :hover styles will be visible
When you hover and interact with the element above, only the styles applied to :hover
will prevail as long as you are still hovering over it. As we’ve seen, since all three events are applied during a typical click event, the cascade takes over and the last-defined style wins.
This is why it’s important to define these styles in the order in which they typically happen, so it becomes clear to the user when a new interaction is recognised. Typically, a user will first hover over an element, then bring it to focus, then activate it. So, the best way to order your pseudo-class styles are :hover
then :focus
then :active
.
button:hover {
background-color: green;
}
button:focus {
background-color: blue;
}
button:active {
background-color: red;
}
All styles will be visible
Recap #
The :hover
, :focus
, and :active
pseudo-classes allow us to style elements in response to how a user interacts with it. Depending on the device being used, these pseudo-classes become active at different points (or not at all).
:hover |
:focus |
:active |
|
---|---|---|---|
Mouse 🐭 | Yes | Yes | Yes |
Keyboard ⌨️ | No | Yes | Yes |
Touchscreen 📱 | Yes (on click) | Yes* (on click) | Yes* (on click) |
* Will not apply on mobile (iOS) Safari