Pseudo-Classes and Pseudo-Elements
Pseudo-classes and pseudo-elements let you style elements based on their state, position, or specific parts of their content, without adding extra HTML.
Pseudo-classes
A pseudo-class targets an element in a particular state. You add it after the selector with a single colon (:).
selector:pseudo-class {
property: value;
}
User interaction
:hover, :focus, and :active respond to what the user is doing.
/* unvisited link */
a:link {
color: #3b82f6;
}
/* visited link */
a:visited {
color: #7c3aed;
}
/* mouse over link */
a:hover {
color: #1d4ed8;
text-decoration: underline;
}
/* link being clicked */
a:active {
color: #1e40af;
}
Form states
These pseudo-classes let you style form inputs based on their current state.
/* input when it has keyboard focus */
form input:focus {
border: 2px solid #3b82f6;
outline: none;
}
/* input when its value passes HTML validation */
form input:valid {
border: 2px solid #16a34a;
}
/* input when its value fails HTML validation */
form input:invalid {
border: 2px solid #dc2626;
}
/* disabled input */
input:disabled {
background-color: #f3f4f6;
cursor: not-allowed;
}
/* checked checkbox or radio button */
input:checked {
accent-color: #3b82f6;
}
Structural pseudo-classes
These target elements based on their position in the document.
:first-child and :last-child target the first or last child of a parent.
ul li:first-child {
font-weight: bold;
}
ul li:last-child {
border-bottom: none;
}
:nth-child() is more flexible. It accepts a number, even, odd, or a formula like 3n.
/* Target every other table row */
tr:nth-child(even) {
background-color: #f3f4f6;
}
/* Target every third list item */
li:nth-child(3n) {
font-weight: bold;
}
/* Target the second item */
li:nth-child(2) {
color: #3b82f6;
}
:not()
:not() selects elements that do NOT match a selector. Useful for styling everything except a specific case.
/* Style all buttons except the primary one */
button:not(.primary) {
background-color: transparent;
border: 1px solid #d1d5db;
}
:is() and :where()
Both let you group multiple selectors to avoid repetition. The difference is specificity: :is() takes on the specificity of its most specific argument; :where() always has zero specificity.
/* Instead of writing h1 a, h2 a, h3 a */
:is(h1, h2, h3) a {
color: inherit;
}
/* Same result but with zero specificity, easier to override */
:where(h1, h2, h3) a {
color: inherit;
}
For a full list of pseudo-classes, see the MDN pseudo-classes reference .
Pseudo-elements
A pseudo-element styles a specific part of an element rather than the element itself. Use a double colon (::), which is the modern standard.
selector::pseudo-element {
property: value;
}
::before and ::after
These inject generated content before or after an element’s actual content. They require a content property (it can be an empty string).
/* Add a required field marker */
.required-field::after {
content: " *";
color: #dc2626;
}
A common use is decorative shapes or icons that should not be in the HTML.
::first-letter
Styles the first letter of a block of text. Good for drop caps.
p::first-letter {
font-size: 2.5em;
font-weight: bold;
float: left;
margin-right: 4px;
line-height: 1;
}
::first-line
Styles the first line of a paragraph. The amount of text this covers depends on the viewport width.
p::first-line {
font-weight: bold;
font-size: 1.1em;
}
::selection
Styles text that the user has highlighted by clicking and dragging.
p::selection {
background-color: #bfdbfe;
color: #1e3a8a;
}
::placeholder
Styles the placeholder text in an input or textarea.
input::placeholder {
color: #9ca3af;
font-style: italic;
}
::marker
Styles the bullet or number on a list item.
li::marker {
color: #3b82f6;
font-weight: bold;
}
For a full list of pseudo-elements, see the MDN pseudo-elements reference .
What to read next
- Responsive Design : media queries, fluid units, and container queries
- Transform : moving, rotating, scaling, and animating elements