Pseudo-Elements
Pseudo-elements let you style a part of an element, or add decoration, without touching the HTML: a drop cap, an icon before a link, a custom bullet.
On this page · 5 min · Intermediate
On this page
- Learning objectives
- Explanation
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 28, 2026
Related tutorials
Learning objectives#
- Add decorations with ::before and ::after
- Style parts of text with ::first-letter and ::first-line
- Style placeholders, selections and list markers
- Know when content belongs in HTML instead
Explanation#
Pseudo-elements use two colons: p::first-line. They target something that is not a real element in the HTML.
::before and ::after insert a box as the first or last child of an element. They need content: "" to appear, even if empty.
::first-letter styles the first letter (drop caps); ::first-line styles the first line, whatever its length.
::placeholder styles input hint text; ::selection styles highlighted text; ::marker styles list bullets and numbers.
Content added with ::before/::after is decoration. Screen readers may or may not read it, and users cannot copy it — keep real information in HTML.
Code example: Decorations without extra HTML#
<style>
body { font-family: Georgia, serif; max-width: 60ch; }
.story::first-letter { float: left; font-size: 3.2em; line-height: 1; padding-right: 6px; color: #b45309; }
.story::first-line { font-variant: small-caps; }
.required::after { content: " *"; color: #dc2626; }
a[href^="http"]::after { content: " ↗"; font-size: 0.8em; }
.quote { position: relative; padding-left: 28px; font-style: italic; }
.quote::before { content: "“"; position: absolute; left: 0; top: -12px; font-size: 3rem; color: #94a3b8; }
ul.ticks li::marker { content: "✓ "; color: #16a34a; }
::selection { background: #fde68a; }
input::placeholder { color: #94a3b8; font-style: italic; }
</style>
<p class="story">Once upon a time in a small village by the river, there lived a potter who made the most beautiful lamps in the land.</p>
<label class="required">Email</label> <input placeholder="you@example.com">
<p>Read more on <a href="https://developer.mozilla.org">MDN</a>.</p>
<p class="quote">Simplicity is the soul of efficiency.</p>
<ul class="ticks"><li>Fast</li><li>Accessible</li></ul>
A story with a large orange drop cap and small-caps first line, a red asterisk after “Email”, an arrow after the external link, a big decorative quote mark, green tick bullets and yellow text selection.
Step-by-step explanation#
- ::first-letter floats a large first letter for a classic drop cap.
- .required::after adds a red asterisk without editing every label.
- a[href^="http"]::after marks external links automatically.
- .quote::before draws a decorative quote mark positioned in the padding.
- ::marker replaces the default bullets with ticks.
- ::selection changes the highlight colour when text is selected.
Real-world use case#
Pseudo-elements build tooltips, ribbons, custom checkbox shapes, overlay gradients on images and decorative underlines — all without cluttering the HTML.
Common mistakes#
::before and ::after render nothing without a content property. Use content: "" for purely visual shapes.
Void/replaced elements have no children, so ::before and ::after do not work on them. Wrap them instead.
Prices or instructions in CSS content cannot be selected and may be skipped by assistive technology.
Best practices#
- Use pseudo-elements for decoration only
- Use content: "" with width/height for shapes
- Use two colons for pseudo-elements, one for pseudo-classes
- Remember ::before/::after are children — position: relative on the parent helps place them
Remember this#
Two colons = a “ghost” part of the element.
No content, no show — ::before/::after need content.
Decoration in CSS, information in HTML.
Practice exercise#
Your task: Add a small grey “#” before every h2, without changing the HTML.
Need a hint?
Show solution
h2::before {
content: "# ";
color: #94a3b8;
}
Mini quiz#
What is required for ::after to appear?
Want more? Practise all CSS MCQs · CSS interview questions
My notes#
Saved in this browser.