An HTML element is never fixed in place: a link can be hovered, a checkbox can be checked, a field can be empty or in an error state. Pseudo-classes give CSS the ability to react to these states, without ever touching the markup.
They are among the most used tools in the language, often before the term "pseudo-class" is even known, since :hover or :first-child tend to show up very early when learning CSS.
Definition
A pseudo-class is a keyword added to a selector, preceded by a single colon, that targets an element based on a particular state or position, rather than by its tag, class, or attribute.
Common examples
/* state: while the mouse is hovering */
a:hover {
text-decoration: underline;
}
/* state: field currently focused */
input:focus {
border-color: #4a90d9;
}
/* position: first child of the parent */
li:first-child {
font-weight: bold;
}
/* position: nth child, here every even one */
tr:nth-child(2n) {
background-color: #f5f5f5;
}Some pseudo-classes react to an interaction, like :hover or :focus. Others describe a position within a list of children, like :first-child, :last-child, or :nth-child(), which accepts a formula to target every Nth element.
One colon, never two
Pseudo-class syntax always uses a single colon, unlike the Pseudo-element, which uses two. That distinction is not cosmetic: a pseudo-class targets an element that already exists in the HTML, while a pseudo-element creates a rendered fragment with no equivalent in the markup, such as the first character of a paragraph or content injected before an element.
| Pseudo-class | Target |
|---|---|
:hover | Element under the mouse cursor |
:focus | Element that has keyboard focus |
:first-child | First child of its parent |
:nth-child() | Child at a calculated position |
:disabled | Disabled form field |
Combining pseudo-classes
Several pseudo-classes can be chained on the same selector to refine the target, for example a:hover:not(.disabled), which applies a style on hover except on disabled links. The order in which pseudo-classes are written has no effect on the result.
:focus deserves as much attention as :hover for accessibility.Form pseudo-classes
Forms come with a dedicated set of pseudo-classes that reflect a field's real state without a single line of JavaScript. :required targets a mandatory field, :valid and :invalid react to the browser's native validation, and :checked targets a checked checkbox or a selected radio button. These pseudo-classes make it possible to build immediate visual feedback, like a green border on a correctly filled field, without depending on a script to check the value on every keystroke. They naturally combine with :hover and :focus to cover every state a field goes through, from the first keystroke to the form's final validation. Our HTML and CSS course walks through this native validation step by step, to build forms that give clear visual feedback without depending on JavaScript.
/* required field left empty, shown in red */
input:required:invalid {
border-color: #e63946;
}
/* checked box, colored background on its label */
input:checked + label {
background-color: #eaf3ff;
}Frequently asked questions
No, pseudo-classes are part of the CSS specification and of the browser that implements it. A custom one cannot be created the way a new HTML class can.
Yes, a pseudo-class applies to any element that matches the described state or position at a given moment, which can mean a single element or several at the same time.
That is often the :active pseudo-class at work: it only applies during the very short time an element is actively being pressed, and disappears as soon as the click is released.