CSS Pseudo-classes

Style elements based on their state or position

🎯 What are CSS Pseudo-classes?

Pseudo-classes are keywords that specify a special state of an element. They allow you to style elements when they're being hovered over, focused, or in specific positions.


/* Style links when hovered */
a:hover {
    color: red;
    text-decoration: underline;
}
                                    

Common Pseudo-classes

👆

:hover

When mouse is over element

button:hover { background: blue; }
🎯

:focus

When element has focus

input:focus { border: 2px solid blue; }
👆

:active

When element is being clicked

button:active { transform: scale(0.95); }
🔗

:visited

For visited links

a:visited { color: purple; }

🔹 Interactive Button Example

Interactive button implementations demonstrate CSS pseudo-classes including :hover, :focus, and :active creating visual feedback states. These states provide essential user experience affordances indicating interactive availability and activation status. Implementation combines transition animations with appropriate timing functions for smooth state changes. Accessible buttons include proper ARIA attributes and keyboard navigation support, ensuring universal usability that positively impacts engagement metrics.

<!-- HTML -->
<button class="interactive-btn">Hover Me!</button>
/* CSS */
.interactive-btn {
    background-color: #4CAF50;
    color: white;
    padding: 15px 30px;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
    transition: all 0.3s ease;
}

.interactive-btn:hover {
    background-color: #45a049;
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}

.interactive-btn:active {
    transform: translateY(0);
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}

.interactive-btn:focus {
    outline: 3px solid #81C784;
}

Output (try hovering and clicking):

🔹 Structural Pseudo-classes

Structural pseudo-classes target HTML elements based on their position within the document tree or a parent container. Key selectors include :first-child to style the first element, :last-child for the last, and :nth-child() for precise positional targeting—such as odd/even rows for table striping. :nth-of-type() filters by element type, enabling advanced layouts like alternating card styles. These selectors enhance maintainability by removing the need for manual class assignments, keeping HTML clean. They are essential for creating dynamic, data-driven interfaces where content order may change, ensuring consistent styling without extra markup.

<!-- HTML -->
<ul class="item-list">
    <li>First item</li>
    <li>Second item</li>
    <li>Third item</li>
    <li>Fourth item</li>
    <li>Last item</li>
</ul>
/* CSS */
.item-list li:first-child {
    background-color: lightgreen;
    font-weight: bold;
}

.item-list li:last-child {
    background-color: lightcoral;
    font-weight: bold;
}

.item-list li:nth-child(even) {
    background-color: #f0f0f0;
}

.item-list li:nth-child(3) {
    background-color: lightyellow;
    border-left: 4px solid orange;
}

Output:

  • First item
  • Second item
  • Third item
  • Fourth item
  • Last item

🔹 Form Pseudo-classes

Form pseudo-classes apply styles based on the state or validity of form elements, improving user interaction and accessibility. :focus highlights the active input, :checked styles selected checkboxes/radio buttons, and :disabled visually greys out non-interactive fields. Validation states like :valid and :invalid provide immediate feedback using color cues (green for correct, red for errors). :required and :optional differentiate mandatory fields. These pseudo-classes help guide users through forms, reduce submission errors, and enhance UX by making interface states clear, which can improve form completion rates and overall site engagement.

<!-- HTML -->
<form class="demo-form">
    <input type="text" placeholder="Enter your name" required>
    <input type="email" placeholder="Enter your email" required>
    <input type="checkbox" id="agree">
    <label for="agree">I agree to terms</label>
</form>
/* CSS */
.demo-form input:focus {
    border: 2px solid #4CAF50;
    outline: none;
    box-shadow: 0 0 5px rgba(76, 175, 80, 0.3);
}

.demo-form input:valid {
    border-color: green;
}

.demo-form input:invalid {
    border-color: red;
}

.demo-form input:checked + label {
    color: green;
    font-weight: bold;
}

.demo-form input:disabled {
    background-color: #f5f5f5;
    cursor: not-allowed;
}

Output (try typing in the fields):

🔹 Link States

Link state pseudo-classes style anchor elements based on user interaction, following the LVHA order: :link, :visited, :hover, :active. :link defines unvisited links, typically blue. :visited applies to previously clicked links, often purple. :hover triggers on mouse-over for visual feedback. :active styles the link during the click moment. Maintaining this order prevents specificity conflicts and ensures predictable behavior. Properly styled link states enhance navigation clarity, improve user experience by providing interactive feedback, and support accessibility for keyboard and screen reader users. Clear visual cues also encourage deeper site exploration, boosting SEO through improved engagement metrics.

<!-- HTML -->
<div class="link-demo">
    <a href="#" class="demo-link">Normal Link</a>
    <a href="#" class="demo-link visited-link">Visited Link</a>
</div>
/* CSS - Remember LVHA order! */
.demo-link:link {
    color: blue;
    text-decoration: none;
}

.demo-link:visited {
    color: purple;
}

.demo-link:hover {
    color: red;
    text-decoration: underline;
}

.demo-link:active {
    color: orange;
}

Output (try hovering over the links):

🔹 Advanced Pseudo-classes

Advanced pseudo-classes enable complex selection logic for sophisticated UI patterns and conditional styling. :not() excludes elements matching a selector, useful for applying styles broadly with exceptions. :empty targets elements with no children, allowing hidden placeholder cleanup. :target styles the element referenced in the URL fragment, enabling CSS-only tab systems. :lang() applies locale-specific styles. These selectors reduce JavaScript dependency, enhance performance, and keep stylesheets maintainable. They empower developers to create responsive, interactive components—like filtered galleries or dynamic notifications—purely with CSS, improving page load times and core web vitals, which are critical SEO ranking factors.

Useful Advanced Pseudo-classes:

  • :not() - Selects elements that don't match a selector
  • :nth-of-type() - Selects elements by type and position
  • :empty - Selects elements with no content
  • :root - Selects the document root (html element)
/* Examples */
p:not(.special) {
    color: gray;
}

img:nth-of-type(odd) {
    float: left;
}

div:empty {
    display: none;
}

:root {
    --main-color: #4CAF50;
}

🧠 Test Your Knowledge

What is the correct order for link pseudo-classes?