Not every piece of content that shows up on screen actually exists in the HTML. The pseudo-element is the tool that lets CSS create these rendered fragments directly from the stylesheet.
It is a family of selectors distinct from pseudo-classes, though the two are often confused at first, since the syntax only differs by a single colon.
Definition
A pseudo-element is a keyword added to a selector, preceded by two colons, that targets a specific portion of an element's rendering, such as its first line, its first character, or generated content that has no existence in the HTML document.
The most common pseudo-elements
/* content injected before the element */
.badge::before {
content: "★";
margin-right: 4px;
}
/* content injected after the element */
.external-link::after {
content: " ↗";
}
/* first line of a block of text */
p::first-line {
font-weight: bold;
}
/* text shown in an empty field */
input::placeholder {
color: #999;
}The ::before and ::after pseudo-elements are probably the most used: they let you inject visual content, like an icon or an arrow, without adding a single element to the HTML. Other pseudo-elements target more subtle fragments, such as ::first-letter for the first letter of a paragraph or ::selection for text selected by the user.
Double colon versus single colon
Modern syntax reserves the double colon for pseudo-elements and the single colon for Pseudo-class, which makes it possible to spot the two families instantly just by reading a selector. Some older pseudo-elements like ::before still accept the single colon spelling for compatibility with very old CSS, but the double colon syntax remains the recommended convention today.
| Aspect | Pseudo-class | Pseudo-element |
|---|---|---|
| Syntax | One colon | Two colons |
| What it targets | A state or a position | A rendered fragment |
| Exists in the HTML | Yes, already present | No, generated by CSS |
Real use cases
Pseudo-elements are used to add decorative icons with no extra tag, to build automatic counters inside a list, to run a clearfix to contain floated elements, or even to build tooltips entirely in CSS thanks to content injected through content combined with conditional display on hover.
::before or ::after only shows up if the content property is set, even with an empty value like content: "". Forgetting that property is the number one reason a pseudo-element stays invisible.Two lesser known pseudo-elements
Beyond ::before, ::after, ::first-line, and ::placeholder, two other pseudo-elements deserve a mention. ::first-letter targets only the first letter of a block of text, a classic way to build a typographic drop cap at the start of a paragraph. ::selection targets the text a user selects with the mouse, which makes it possible for example to replace the browser's default highlight color with a shade that matches the site's visual identity.
/* drop cap on the first paragraph of an article */
article p:first-of-type::first-letter {
font-size: 2.5em;
float: left;
line-height: 0.8;
}
/* custom selection color */
::selection {
background-color: #ffe66d;
}Frequently asked questions
::before not show up on screen?The most common cause is a missing content property. Without it, the browser generates no box to display, even if every other property is set correctly. This is the number one beginner mistake, often made after copying an incomplete code snippet found online.
Not directly: a pseudo-element's content is fixed inside the stylesheet. It can, however, be made to vary through a CSS custom property updated by JavaScript.
No, a pseudo-element does not exist in the DOM and therefore cannot be selected with methods like querySelector. Only its style can be changed, indirectly, through classes or CSS custom properties.