CSS Pseudo-classes
A pseudo-class selects an element when it is in a special state or a special position, without adding any class in the HTML.
Syntax
Write a colon : and the name straight after a selector, with no space.
Example
selector:pseudo-class {
property: value;
}You already met :hover in the Selectors chapter. There are many more.
User Action Pseudo-classes
These react to what the user is doing with the mouse, finger or keyboard.
| Pseudo-class | Matches when |
|---|---|
:hover | The mouse pointer is over the element |
:active | The element is being pressed |
:focus | The element has keyboard focus (for example, an input you clicked) |
:focus-visible | It has focus and the browser thinks a focus ring should show |
:focus-within | The element or anything inside it has focus |
Example
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.btn {
background-color: #264de4;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
}
.btn:hover { background-color: #1d3bb3; }
.btn:active { transform: scale(0.95); }
form {
padding: 12px;
border: 2px solid #dddddd;
margin-top: 16px;
}
form:focus-within { border-color: #264de4; }
input:focus { outline: 3px solid orange; }
</style>
</head>
<body>
<button class="btn">Press me</button>
<form>
<label>Your name: <input type="text"></label>
</form>
</body>
</html>Try it Yourself »Click into the input. The input gets an orange outline, and the whole form gets a blue border because of :focus-within.
Form State Pseudo-classes
These help you style form fields based on their state.
| Pseudo-class | Matches |
|---|---|
:checked | A ticked checkbox or selected radio button |
:disabled / :enabled | Fields that are turned off or on |
:required / :optional | Fields with or without the required attribute |
:valid / :invalid | Fields whose value passes or fails the rules |
:user-invalid | Invalid, but only after the user has changed the field |
:placeholder-shown | An input that is still showing its placeholder |
Example
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
input {
padding: 8px;
border: 2px solid #cccccc;
border-radius: 4px;
display: block;
margin-bottom: 10px;
}
input:user-invalid { border-color: crimson; }
input:valid { border-color: seagreen; }
input:disabled { background-color: #eeeeee; }
input[type="checkbox"]:checked + span {
font-weight: bold;
color: seagreen;
}
</style>
</head>
<body>
<input type="email" placeholder="Email address" required>
<input type="text" value="Admission No: 2026-114" disabled>
<label><input type="checkbox"> <span>I agree to the rules</span></label>
</body>
</html>Try it Yourself »Type a wrong email and click outside the box to see the red border. :user-invalid waits until the user has touched the field, so the form does not shout at people before they start typing.
Position Pseudo-classes
These select an element by its place among its brothers and sisters (siblings).
| Pseudo-class | Selects |
|---|---|
:first-child | The first child of its parent |
:last-child | The last child |
:only-child | A child with no siblings |
:nth-child(3) | The 3rd child |
:nth-child(odd) / :nth-child(even) | Every odd or even child |
:nth-child(3n) | Every 3rd child: 3, 6, 9... |
:nth-last-child(2) | The 2nd child counting from the end |
:first-of-type | The first element of its tag type, like the first <p> |
Example
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
li { padding: 8px; list-style: none; }
li:nth-child(even) { background-color: #eef2ff; }
li:first-child { font-weight: bold; color: #264de4; }
li:last-child { border-bottom: 2px solid #264de4; }
</style>
</head>
<body>
<ul>
<li>Class 10 Results</li>
<li>Ali - 1012 marks</li>
<li>Sana - 998 marks</li>
<li>Hamza - 975 marks</li>
<li>Fatima - 960 marks</li>
</ul>
</body>
</html>Try it Yourself »The :not() Pseudo-class
:not() selects everything that does not match the selector inside it. A popular use is adding a line between items, but not after the last one:
Example
.menu li:not(:last-child) {
border-bottom: 1px solid #dddddd;
}Other Useful Ones
:rootselects the<html>element; it is where CSS variables usually live:emptyselects elements with nothing inside them:targetselects the element whose id matches the#partin the URL:visitedstyles links the user has already opened
You can combine pseudo-classes: a:not(.button):hover means "a link without the class button, while it is being hovered".
Exercise
Exercise
Which selector gives every second row of a table a background colour?
