A pseudo-class is a keyword added to a CSS selector, prefixed by a colon (:), that defines a specific state or condition of an element.
Instead of relying on JavaScript to change classes when a user interacts with an element, pseudo-classes allow you to style elements dynamically—like a hovered button, the first child of a container, or a checked input field.
Syntax:
selector:pseudo-class {
/* styles */
}
These pseudo-classes respond directly to how the user interacts with the webpage using their mouse or keyboard.
| Pseudo-Class | Description |
|---|---|
:hover |
Applies when the user hovers their cursor over an element. |
:focus |
Applies when an element receives focus (e.g., a text input is clicked). |
:active |
Applies at the exact moment an element is being clicked/pressed. |
:visited |
Applies to anchor (<a>) links the user has already visited. |
:link |
Applies to anchor links that the user has not visited yet. |
:focus-visible |
Applies when an element is focused, but only if the focus is visible (e.g., navigating via the 'Tab' key instead of a mouse click). |
:focus-within |
Applies to a parent element if it, or any of its descendants, currently has focus. |
<style>
a:link { color: navy; } a:visited { color: purple; } a:hover { color: lightblue; }
button { background-color: navy; color: white; transition: 0.2s; }
button:hover { background-color: lightblue; color: navy; }
button:active { transform: scale(0.95); }
input:focus { border: 3px solid navy; outline: none; }
.form-container:focus-within { border-color: navy; background-color: #f4f4f9; }
</style>
<a href="#">Hover me!</a>
<button>Click Me</button>
<div class="form-container">
<input type="text" placeholder="Click to focus...">
</div>
These pseudo-classes allow you to select elements based on their exact position within the HTML Document Object Model (DOM) tree, without needing to add extra classes to your HTML.
| Pseudo-Class | Description |
|---|---|
:first-child |
Matches the very first child element of its parent. |
:last-child |
Matches the very last child element of its parent. |
:nth-child(n) |
Matches the nth child of its parent (e.g., nth-child(2) or nth-child(even)). |
:nth-last-child(n) |
Matches the nth child, counting backwards from the end. |
:first-of-type |
Matches the first instance of a specific element type within a parent. |
:last-of-type |
Matches the last instance of a specific element type within a parent. |
:nth-of-type(n) |
Matches the nth instance of a specific type. |
:only-child |
Matches an element only if it is the sole child of its parent. |
:only-of-type |
Matches an element if it is the only instance of its type within the parent. |
:empty |
Matches elements that have absolutely no children (including no text/spaces). |
<style>
.list-container li { list-style: none; padding: 8px; background: #eee; }
.list-container li:first-child { background: navy; color: white; }
.list-container li:last-child { background: lightblue; color: navy; }
.list-container li:nth-child(even) { border-left: 5px solid navy; }
div:empty { height: 30px; background: lightcoral; }
</style>
<ul class="list-container">
<li>1. First Child</li>
<li>2. Second (Even)</li>
<li>3. Third</li>
<li>4. Fourth (Even)</li>
<li>5. Last Child</li>
</ul>
<div></div>
Form pseudo-classes are incredibly powerful for creating responsive, accessible user interfaces based on form validation and user input states.
| Pseudo-Class | Description |
|---|---|
:checked |
Matches checkboxes or radio buttons that are currently selected. |
:disabled |
Matches form elements that are disabled (cannot be interacted with). |
:enabled |
Matches form elements that are active and interactive. |
:required |
Matches inputs that have the HTML required attribute. |
:optional |
Matches inputs that do not have the required attribute. |
:valid |
Matches inputs where the entered data passes validation (e.g., a correct email format). |
:invalid |
Matches inputs where the entered data fails validation. |
:in-range |
Matches number inputs where the value is within the specified min and max. |
:out-of-range |
Matches number inputs where the value falls outside the limits. |
:read-only |
Matches inputs that have the readonly attribute applied. |
:read-write |
Matches elements that are editable by the user. |
<style>
input:valid { border: 2px solid green; }
input:invalid { border: 2px solid red; }
input:disabled { background: #ccc; }
input:read-only { background: #f0f0f0; }
input[type="checkbox"]:checked { outline: 3px solid navy; }
</style>
<input type="email" required placeholder="Enter email">
<input type="text" disabled value="Cannot edit">
<input type="text" readonly value="Read-only">
<label>
<input type="checkbox"> Check me!
</label>
Which pseudo-class would you use to change the style of an element at the exact moment a user clicks down on it?