CSS Pseudo Elements
By Flavio
Published · Updated
Tagged: CSS
Learn how CSS pseudo elements like before, after, first-letter, and first-line style specific parts of an element and insert content before or after it.
Pseudo-elements are used to style a specific part of an element.
They start with a double colon ::.
Sometimes you will spot them in the wild with a single colon. That legacy syntax is valid only for
::before,::after,::first-lineand::first-letter(CSS2). Newer pseudo-elements require::. Use two colons to distinguish them from pseudo-classes.
::before and ::after are probably the most used pseudo-elements. They are used to add content before or after an element, like icons for example.
Here are the most common pseudo-elements. See also CSS selectors.
| Pseudo-element | Targets |
|---|---|
::after |
creates a pseudo-element after the element |
::before |
creates a pseudo-element before the element |
::first-letter |
can be used to style the first letter of a block of text |
::first-line |
can be used to style the first line of a block of text |
::selection |
targets the text selected by the user |
::marker |
list item bullets and numbers (Chrome 86, Firefox 68, Safari 11.1) |
::placeholder |
input placeholder text |
::backdrop |
the box behind a <dialog> opened with showModal(), or a fullscreen element (Safari since 15.4) |
::file-selector-button |
the button of <input type="file"> (Chrome 89, Firefox 82, Safari 14.1) |
Let’s do an example. Say you want to make the first line of a paragraph slightly bigger in font size, a common thing in typography:
p::first-line {
font-size: 2rem;
}
Or maybe you want the first letter to be bolder:
p::first-letter {
font-weight: bolder;
}
::after and ::before are a bit less intuitive. I remember using them when I had to add icons using CSS.
You specify the content property to insert any kind of content after or before an element:
p::before {
content: url(/myimage.png);
}
.myElement::before {
content: "Hey Hey!";
}
::before is generated as the first child of the element. ::after is generated as the last child. Both are inline by default.
content is required
Without content, ::before and ::after do not show up. Same if you set content: none or content: normal. The browser treats that as display: none.
Need an empty box you can size and position, like a decorative square? Set content to an empty string:
.note::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
background: yellow;
margin-right: 8px;
}
You can also pull a value off the HTML with attr():
a::after {
content: ' (' attr(href) ')';
}
That prints the link URL after the link text.
What they cannot do
Generated boxes are not in the DOM. querySelector() cannot find them. You style them in CSS. You cannot attach a click listener to the pseudo-element itself.
They also do not work on replaced elements. The element’s content comes from an outside resource, so the browser has nothing to attach the box to. That includes img, input, textarea, br, iframe and video.
You get one ::before and one ::after per element. If you need a third decorative piece, add a real element, or reuse something like ::marker on a list item.
When to use them
Use a pseudo-element for decoration: an icon, a quote mark, a selected-text highlight.
::selection {
background: yellow;
color: black;
}
Do not put information that the reader needs inside content. Screen readers often skip generated text. If the words matter, put them in the HTML.
My advice is: extra markup when the thing is content, ::before / ::after when it is decoration.
Want me to talk about your product? You can sponsor this site.