Hello! Welcome to your next lesson in our front-end development course.
In our last session, we covered the mobile-first design approach, a strategy centered on progressive enhancement. We learned to build a baseline experience for small screens and then add complexity for larger ones using min-width media queries.
Today, we'll build on that idea of enhancement by focusing on interactivity. This lesson will teach you how to style interactive elements using pseudo-classes including :hover, :focus, and :active. As a UI/UX designer, you know that providing clear visual feedback is fundamental to creating an intuitive and satisfying user experience. These CSS pseudo-classes are the primary tools for bringing those interactive states from your Figma mockups to life in the browser.
1. What are Interactive Pseudo-classes?
A pseudo-class is a CSS keyword that allows you to apply styles to an element when it's in a specific state. The most common states are related to user interaction.
Let's start with a quick reading to define the three core interactive pseudo-classes: :hover, :active, and :focus.
This article from web.dev provides a concise, modern overview of the pseudo-classes that respond to user interaction. It's a great starting point for understanding the basic states.
Read the subsections under 'Interactive states' for :hover, :active, and the beginning of :focus, :focus-within, and :focus-visible. Just focus on the initial definitions for now.
To summarize and clarify:
:hover: Applies when a user's cursor (like a mouse pointer) is over an element. This is your primary tool for indicating that something is clickable or interactive.:active: Applies during the moment an element is being activated—for example, between the mouse button press and its release. This state is often used to give a "pressed" or "depressed" look to buttons.:focus: Applies when an element has been selected by the user, either by clicking on it (like a form input) or by navigating to it with the keyboard (using the Tab key).
A Classic Example: Styling Links
Links (<a> tags) are the classic example where these states are used together. There's a specific order you should write them in your CSS to ensure they work correctly, often remembered by the mnemonic LVHA: Link, Visited, Hover, Active.
This W3Schools page gives a clear example of the LVHA order for styling links. It's a foundational concept in CSS interactivity.
Read the section 'Pseudo-classes Used on Links' and pay close attention to the note about the required order of the rules.
Here is a practical example for a button, which combines these states:
.my-button {
background-color: #007bff; /* Blue */
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.2s ease-in-out; /* Smooth transition */
}
/* State 1: Hover - indicates interactivity */
.my-button:hover {
background-color: #0056b3; /* Darker blue */
}
/* State 2: Focus - for accessibility and keyboard navigation */
.my-button:focus {
outline: 3px solid #0056b3;
outline-offset: 2px;
}
/* State 3: Active - gives feedback during the click */
.my-button:active {
background-color: #004085; /* Even darker blue */
transform: translateY(1px); /* Slight 'press down' effect */
}
2. The Critical Role of Focus Styles
While :hover and :active are important for mouse users, the :focus state is absolutely critical for accessibility and keyboard navigation. Users who don't use a mouse rely on the visual focus indicator (usually an outline) to know which element is currently active.
Unfortunately, a common mistake is to remove this outline because it doesn't fit the design:
/* BAD PRACTICE - Do not do this without a replacement! */
button:focus {
outline: none;
}
Removing the focus outline without providing a clear, visible alternative makes your site unusable for many people. As a designer, it's essential to design beautiful and accessible focus states.
A Smarter Approach: :focus-visible
Modern browsers offer a brilliant solution to this design-vs-accessibility dilemma: the :focus-visible pseudo-class. It works intelligently:
- It shows the focus style when a user navigates with a keyboard (e.g., using the Tab key).
- It hides the focus style for mouse clicks on elements like buttons, where the user's intent is already clear from the click itself. (Note: It still shows for inputs, where focus is expected).
This provides the best of both worlds: a clean interface for mouse users and essential feedback for keyboard users.
The following video provides an excellent demonstration of the difference between :focus and :focus-visible.
Quick guide to CSS focus states
Kevin Powell gives a fantastic, quick guide on focus states. He clearly demonstrates the problem with default focus styles on buttons and how :focus-visible provides a much better user experience.
Watch from 02:52 to 05:49. Pay close attention to how the button behaves differently with :focus versus :focus-visible when using the mouse versus the keyboard.
Here’s how you would implement this in your CSS:
/* Style for keyboard-only focus */
.my-button:focus-visible {
outline: 3px solid #0056b3;
outline-offset: 2px;
}
/* Optional: You can remove the outline for non-keyboard focus,
but :focus-visible handles this gracefully on its own in modern browsers. */
.my-button:focus:not(:focus-visible) {
outline: none;
}
3. Enhancing UX with :focus-within
There's one more powerful focus-related pseudo-class: :focus-within. This applies styles to a parent element whenever one of its child elements receives focus.
This is incredibly useful for forms. Imagine you have a label and an input field wrapped in a div. With :focus-within, you can highlight the entire group when the user focuses on the input field.
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" class="form-input">
</div>
.form-group {
border: 2px solid #ccc;
padding: 15px;
border-radius: 5px;
transition: border-color 0.2s ease;
}
/* When the input inside .form-group gets focus... */
.form-group:focus-within {
border-color: #007bff; /* ...change the border of the parent div */
}
This technique provides a larger, clearer visual indicator of the user's current location, greatly improving the form-filling experience.
This next video explains :focus-within and also provides a great recap on styling focus indicators in general.
Elevate User Experience with CSS Focus Pseudo-Classes
This video from Optimistic Web dives into the user experience benefits of focus pseudo-classes and offers a great explanation of :focus-within.
Watch from 02:06 to 05:01. The first part (02:06-03:57) gives a great overview of the outline property. The second part (03:57-05:01) demonstrates the :focus-within use case.
Conclusion
You now have the tools to create interfaces that not only look good but also feel responsive and are accessible to all users. In your design work, you're likely already creating variants for "Hover," "Pressed," and "Focused" states in Figma. Now you know the exact CSS pseudo-classes needed to implement them.
Key Takeaways:
- Pseudo-classes style an element based on its current state.
:hover,:active, and:focusare the foundational pseudo-classes for providing interactive feedback.- Focus styles are not optional; they are a critical accessibility feature. Never remove the
outlinewithout providing a clear visual replacement. :focus-visibleis the modern standard for applying focus styles, offering a better UX by showing them only when necessary (primarily for keyboard navigation).:focus-withinis a powerful tool for enhancing UX in complex components like forms by styling a parent element when a child is focused.
In our next lesson, we'll explore a related concept: pseudo-elements. While pseudo-classes style an element in a certain state, pseudo-elements (::before and ::after) allow you to style specific parts of an element, or even add decorative content, without adding extra HTML.
Can't find a good explanation? Sign up and we'll make it for you
Sign up