CSS Pseudo-Elements
A pseudo-element lets you style a specific part of an element, or even create entirely new visual content without adding extra HTML tags. They use double colons (::) to distinguish them from pseudo-classes.
Think of pseudo-elements as invisible editing markers inside your content — you can style the first letter of a paragraph, insert a decorative symbol before a heading, or style text the user has selected, all without touching the HTML.
Pseudo-Element vs Pseudo-Class
DIAGRAM — Pseudo-Class vs Pseudo-Element:
:hover → targets the WHOLE element in a certain STATE
::first-letter → targets a PART of the element's content
Both use the same colon notation, but double colons (::)
are the modern standard for pseudo-elements.
::before — Insert Content Before
::before creates a virtual element that appears before the element's actual content. You must use the content property — even if you set it to an empty string.
h2::before {
content: "📌 ";
}
DIAGRAM — ::before in action:
HTML: <h2>Introduction</h2>
Output: 📌 Introduction
The emoji is not in the HTML.
CSS ::before created it.
Common Use: Decorative Labels
.required-field::before {
content: "* ";
color: red;
font-weight: bold;
}
Common Use: Icons from CSS
blockquote::before {
content: "\201C"; /* left double quotation mark " */
font-size: 3rem;
color: lightgray;
display: block;
}
::after — Insert Content After
::after works exactly like ::before but places the virtual element after the element's content.
a[target="_blank"]::after {
content: " ↗";
font-size: 0.8em;
color: gray;
}
This adds an arrow icon after every external link automatically — no extra HTML needed.
Common Use: Clearfix
Before Flexbox and Grid, developers used ::after to fix float layout issues:
.clearfix::after {
content: "";
display: block;
clear: both;
}
Common Use: Tooltip Arrows
.tooltip::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
border: 6px solid transparent;
border-top-color: black;
}
::before and ::after as Layout Elements
When you set display: block or position: absolute on ::before or ::after, they become full layout elements — useful for decorative shapes, backgrounds, and badges.
DIAGRAM — ::before as a decorative bar:
h2::before {
content: "";
display: block;
width: 40px;
height: 4px;
background: blue;
margin-bottom: 8px;
}
Visual output:
──── ← blue bar from ::before
My Heading Text
::first-letter — Style the First Character
::first-letter targets the very first letter of a block-level element. This is the classic "drop cap" technique used in magazines and books.
p::first-letter {
font-size: 3rem;
font-weight: bold;
float: left;
line-height: 1;
margin-right: 4px;
color: darkred;
}
DIAGRAM — Drop Cap:
T his is the beginning of a long paragraph.
↑
The "T" is large, bold, and floated left.
The rest of the text wraps around it.
::first-letter only works on block-level elements like <p>, <div>, or headings.
::first-line — Style the First Line
::first-line styles only the first displayed line of text. The "first line" changes dynamically as the window is resized — CSS handles this automatically.
p::first-line {
font-variant: small-caps;
letter-spacing: 2px;
color: gray;
}
DIAGRAM — ::first-line:
FIRST LINE STYLED IN SMALL CAPS
This is the second line, normal style.
And this is the third line, also normal.
::selection — Style Highlighted Text
::selection applies to text the user highlights with a mouse or keyboard.
::selection {
background-color: #ffcc00;
color: black;
}
/* Or target specific elements */
p::selection {
background-color: darkblue;
color: white;
}
Only color, background-color, and a few other properties work on ::selection. Complex layout properties are ignored.
::placeholder — Style Input Placeholder Text
The placeholder text inside an input shows before the user types. ::placeholder styles it.
input::placeholder {
color: #aaa;
font-style: italic;
}
DIAGRAM — ::placeholder:
[ Enter your email address... ]
↑ This greyed-out hint text is the placeholder
::marker — Style List Bullets and Numbers
::marker targets the bullet or number in front of a list item.
li::marker {
color: red;
font-size: 1.2em;
}
/* Custom marker content */
li.done::marker {
content: "✅ ";
}
Rules for ::before and ::after
- The
contentproperty is required. Without it, the pseudo-element does not render at all. - Use
content: ""for decorative shapes that need no text. - They are inline by default. Add
display: blockordisplay: inline-blockto use width and height. - They inherit styles from their parent element.
- They appear in the rendered page but not in the actual HTML source.
Pseudo-Elements Quick Reference
| Pseudo-Element | What It Targets |
|---|---|
| ::before | Virtual element inserted before content |
| ::after | Virtual element inserted after content |
| ::first-letter | The first character of a block element |
| ::first-line | The first displayed line of a block element |
| ::selection | Text highlighted by the user |
| ::placeholder | Input placeholder text |
| ::marker | List item bullet or number |
Pseudo-elements give you styling hooks into parts of your content that no HTML element wraps — keeping your markup lean while achieving rich visual results.
