Pseudo-classes are special keywords added to selectors that specify a special state or position of elements. They let you style elements when users interact with them (like hovering or clicking), when they're in a specific position (like the first child), or when they match certain conditions. They're essential for creating interactive, dynamic user interfaces.
What Are Pseudo-classes?
A pseudo-class is a keyword added to a selector with a single colon (:) that targets elements in a specific state or position. Unlike regular classes that you add in HTML, pseudo-classes are built into CSS and automatically apply based on conditions.
/* Syntax: selector:pseudo-class { properties } */
/* Regular class (added in HTML) */
.button {
background-color: blue;
}
/* Pseudo-class (automatic, built into CSS) */
.button:hover {
background-color: darkblue;
}
/* Another example */
a:visited {
color: purple;
}
input:focus {
border-color: blue;
}Key Difference: Regular classes (.my-class) are written in your HTML and are always present. Pseudo-classes (:hover, :focus) are CSS keywords that apply automatically based on user interaction or element position—you don't add them to HTML.
Types of Pseudo-classes
Pseudo-classes fall into several categories:
- User Action Pseudo-classes: :hover, :active, :focus
- Link Pseudo-classes: :link, :visited
- Input Pseudo-classes: :checked, :disabled, :enabled
- Structural Pseudo-classes: :first-child, :nth-child(), :last-child
- Validation Pseudo-classes: :valid, :invalid, :required
- Other: :not(), :target, :root
User Action Pseudo-classes
These pseudo-classes respond to user interactions, making your interfaces feel dynamic and responsive.
:hover - Mouse Over
The :hover pseudo-class applies when the user moves their mouse over an element. It's one of the most commonly used pseudo-classes for creating interactive effects.
/* Basic hover effect */
button:hover {
background-color: darkblue;
cursor: pointer;
}
/* Hover on links */
a:hover {
color: red;
text-decoration: underline;
}
/* Hover with transition */
.card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
/* Change child elements on parent hover */
.menu-item:hover .submenu {
display: block;
}:hover Pseudo-class Examples
:active - Being Clicked
The :active pseudo-class applies while an element is being activated (typically when it's being clicked). It gives immediate visual feedback.
/* Button being clicked */
button:active {
transform: scale(0.95);
background-color: navy;
}
/* Link being clicked */
a:active {
color: red;
}
/* Combine with other pseudo-classes */
button:hover:active {
transform: scale(0.98);
}:active Pseudo-class Examples
:focus - Keyboard or Click Focus
The :focus pseudo-class applies when an element has focus (selected by clicking or using keyboard navigation). It's crucial for accessibility and form usability.
/* Input field focus */
input:focus {
outline: none;
border-color: blue;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}
/* Textarea focus */
textarea:focus {
border-color: green;
}
/* Button focus (for keyboard navigation) */
button:focus {
outline: 2px solid orange;
outline-offset: 2px;
}
/* Remove focus outline (be careful with accessibility!) */
button:focus {
outline: none; /* Only do this if you add another focus indicator */
}:focus Pseudo-class Examples
Accessibility Reminder: Always provide clear focus indicators for keyboard users. If you remove the default outline with outline: none, make sure to add an alternative visual indicator like a border, shadow, or background color change.
Combining User Action Pseudo-classes
You can combine multiple pseudo-classes for specific states:
/* Hover state for focused input */
input:focus:hover {
border-color: green;
}
/* Active state for hovered button */
button:hover:active {
transform: scale(0.98);
}
/* Not disabled inputs on focus */
input:not(:disabled):focus {
border-color: blue;
}Link Pseudo-classes
These pseudo-classes specifically target link (<a>) elements based on their state.
:link and :visited
:link- Targets unvisited links:visited- Targets links the user has already visited
/* Unvisited links */
a:link {
color: blue;
text-decoration: none;
}
/* Visited links */
a:visited {
color: purple;
}
/* Recommended order: LVHA (Link, Visited, Hover, Active) */
a:link {
color: blue;
}
a:visited {
color: purple;
}
a:hover {
color: red;
text-decoration: underline;
}
a:active {
color: darkred;
}Link Pseudo-classes: :link and :visited
💡 LVHA Order:
Always define link pseudo-classes in this order: Link, Visited, Hover, Active. This ensures they work correctly due to CSS specificity rules. Remember the mnemonic: "LoVe HAte" or "Lord Vader's Handle Appears".
Structural Pseudo-classes
Structural pseudo-classes target elements based on their position in the document tree. They're incredibly useful for styling lists, tables, and repeating elements.
:first-child and :last-child
These select elements that are the first or last child of their parent.
/* First paragraph in any container */
p:first-child {
font-size: 18px;
font-weight: bold;
}
/* Last list item */
li:last-child {
border-bottom: none;
}
/* First child of a specific parent */
.menu li:first-child {
border-top: 2px solid blue;
}
/* Last paragraph in articles */
article p:last-child {
margin-bottom: 0;
}:first-child and :last-child Examples
:nth-child() - Powerful Pattern Matching
The :nth-child() pseudo-class is one of the most powerful selectors. It lets you target elements based on their position using formulas.
/* Target specific position */
li:nth-child(3) {
/* Third item */
color: red;
}
/* Target even items */
tr:nth-child(even) {
background-color: #f0f0f0;
}
/* Target odd items */
tr:nth-child(odd) {
background-color: white;
}
/* Target every 3rd item */
li:nth-child(3n) {
/* 3, 6, 9, 12... */
font-weight: bold;
}
/* Target every 3rd item starting from 2nd */
li:nth-child(3n+2) {
/* 2, 5, 8, 11... */
color: blue;
}
/* Target first 3 items */
li:nth-child(-n+3) {
background-color: yellow;
}:nth-child() Pattern Examples
:nth-child() Formula Patterns
Common :nth-child() Patterns
| Property | Values | Description |
|---|---|---|
:nth-child(3) | Specific number | Selects the 3rd element |
:nth-child(odd) | or 2n+1 | Selects 1st, 3rd, 5th, 7th... (odd elements) |
:nth-child(even) | or 2n | Selects 2nd, 4th, 6th, 8th... (even elements) |
:nth-child(3n) | Every 3rd | Selects 3, 6, 9, 12... |
:nth-child(3n+1) | Every 3rd starting at 1 | Selects 1, 4, 7, 10... |
:nth-child(-n+3) | First N elements | Selects first 3 elements only |
:nth-child(n+4) | From Nth onwards | Selects from 4th element onwards |
:first-of-type and :last-of-type
These select the first or last element of a specific type within their parent, regardless of other elements.
/* First paragraph of its type */
p:first-of-type {
font-size: 20px;
}
/* Last image in container */
img:last-of-type {
margin-bottom: 0;
}
/* Different from :first-child - this ignores other element types */
div p:first-of-type {
/* First <p> in div, even if there's an <h1> before it */
color: blue;
}:first-of-type and :last-of-type Examples
Form Pseudo-classes
These pseudo-classes target form elements based on their state, making form validation and UX much better.
:checked - Radio and Checkbox States
/* Style checked checkboxes */
input[type="checkbox"]:checked {
/* Can't directly style the checkbox, but can style siblings */
}
/* Style label when checkbox is checked */
input[type="checkbox"]:checked + label {
font-weight: bold;
color: green;
}
/* Show content when radio is checked */
input[type="radio"]:checked ~ .content {
display: block;
}:checked Pseudo-class Example
:disabled and :enabled
/* Disabled inputs */
input:disabled {
background-color: #f0f0f0;
cursor: not-allowed;
opacity: 0.6;
}
/* Enabled inputs */
input:enabled {
background-color: white;
}
/* Combine with other pseudo-classes */
input:enabled:focus {
border-color: blue;
}:disabled and :enabled Examples
:valid and :invalid
These pseudo-classes style form inputs based on validation state:
:valid and :invalid Pseudo-classes
Other Useful Pseudo-classes
:not() - Negation Pseudo-class
The :not() pseudo-class selects elements that do NOT match a selector:
/* All paragraphs except those with class "intro" */
p:not(.intro) {
color: gray;
}
/* All list items except the last one */
li:not(:last-child) {
border-bottom: 1px solid #ddd;
}
/* All inputs except disabled ones */
input:not(:disabled) {
border-color: blue;
}
/* Buttons that aren't being hovered */
button:not(:hover) {
opacity: 0.8;
}:empty
Selects elements that have no children (including text):
/* Hide empty paragraphs */
p:empty {
display: none;
}
/* Style empty table cells */
td:empty::before {
content: "—";
color: #ccc;
}:root
Selects the root element of the document (usually <html>). Commonly used for CSS variables:
:root {
--primary-color: #3498db;
--secondary-color: #2ecc71;
--font-size-base: 16px;
}
/* Use the variables */
button {
background-color: var(--primary-color);
font-size: var(--font-size-base);
}Best Practices with Pseudo-classes
1. Maintain LVHA Order for Links
/* Correct order: Link, Visited, Hover, Active */
a:link { color: blue; }
a:visited { color: purple; }
a:hover { color: red; }
a:active { color: darkred; }2. Always Provide Focus Indicators
/* Good: Clear focus indicator */
button:focus {
outline: 2px solid blue;
outline-offset: 2px;
}
/* If removing default outline, add alternative */
input:focus {
outline: none;
border-color: blue;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}3. Use Transitions for Smooth Effects
/* Add transition to base state, not pseudo-class */
button {
background-color: blue;
transition: background-color 0.3s, transform 0.3s;
}
button:hover {
background-color: darkblue;
transform: scale(1.05);
}4. Combine Pseudo-classes Thoughtfully
💡 Pro Tip:
You can chain multiple pseudo-classes, but keep it readable. For example, button:not(:disabled):hover:active targets enabled buttons that are being clicked while hovered—powerful but use sparingly!
Browser Support Note
Most pseudo-classes have excellent browser support in modern browsers. The structural pseudo-classes like :nth-child(), :first-of-type, etc., are supported in all modern browsers (Chrome, Firefox, Safari, Edge). Always test your code, especially if supporting older browsers like IE11.
Key Takeaways
- Pseudo-classes select elements based on state or position
- They use a single colon (:) followed by the pseudo-class name
- :hover, :focus, :active create interactive experiences
- Link pseudo-classes should follow LVHA order (Link, Visited, Hover, Active)
- :nth-child() uses formulas for powerful pattern matching
- :first-child, :last-child target position-based elements
- Form pseudo-classes like :checked, :disabled, :valid improve UX
- Always provide clear focus indicators for accessibility
- :not() excludes elements from selection
- Pseudo-classes can be combined for specific targeting
- Use transitions to make pseudo-class changes smooth
What's Next?
Now that you've mastered pseudo-classes, you're ready to learn about pseudo-elements. While pseudo-classes target elements in a specific state, pseudo-elements let you style specific parts of elements (like the first letter or line) or even insert content before or after elements. They use a double colon (::) and open up even more creative possibilities!
Pseudo-classes are essential for modern, interactive web design. Practice using them to create engaging user interfaces that respond to user actions and provide clear feedback. They're one of the most powerful tools in your CSS toolkit!