::before and ::after
The most-used pseudo-elements. They insert a virtual child node before or after the element's content. Require a content property — even an empty string — to render.
/* Basic usage — content is required */
.icon-label::before {
content: "★ ";
color: gold;
}
.external-link::after {
content: " ↗";
font-size: 0.75em;
color: #888;
}
/* Empty content — used for decorative shapes */
.divider::after {
content: "";
display: block;
height: 2px;
background: linear-gradient(to right, #1572B6, transparent);
margin-top: 1rem;
}
/* Tooltip using ::after + :hover */
[data-tooltip] { position: relative; }
[data-tooltip]::after {
content: attr(data-tooltip); /* read from HTML attribute */
position: absolute;
bottom: calc(100% + 6px);
left: 50%;
transform: translateX(-50%);
background: #333;
color: #fff;
padding: 4px 8px;
border-radius: 4px;
white-space: nowrap;
font-size: 0.8rem;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
[data-tooltip]:hover::after { opacity: 1; }
Classic Clearfix with ::after
/* Modern approach — use display:flow-root or overflow:hidden */
/* But the clearfix is still useful to understand */
.clearfix::after {
content: "";
display: table;
clear: both;
}
Decorative Patterns with ::before / ::after
/* Underline accent on headings */
h2 { position: relative; padding-bottom: 12px; }
h2::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 48px;
height: 3px;
background: #1572B6;
border-radius: 2px;
}
/* Quote marks */
blockquote::before {
content: "\201C"; /* left double quotation mark */
font-size: 4rem;
line-height: 0;
vertical-align: -1rem;
color: #1572B6;
margin-right: 4px;
}
/* Badge / required field marker */
label.required::after {
content: " *";
color: #e44d26;
font-weight: bold;
}
/* Ribbon corner on a card */
.card.ribbon { overflow: hidden; position: relative; }
.card.ribbon::before {
content: "NEW";
position: absolute;
top: 14px;
right: -20px;
background: #e44d26;
color: #fff;
font-size: 0.65rem;
font-weight: 700;
padding: 3px 28px;
transform: rotate(45deg);
letter-spacing: 0.05em;
}
::first-line and ::first-letter
/* ::first-line — styles the first rendered line of a block */
p::first-line {
font-weight: 600;
color: #1a1a1a;
letter-spacing: 0.03em;
}
/* Only certain properties work on ::first-line:
font properties, color, background, word-spacing,
letter-spacing, line-height, text-decoration, text-transform */
/* ::first-letter — styles the first letter/character of a block */
article > p:first-of-type::first-letter {
float: left;
font-size: 3.5rem;
line-height: 0.8;
margin: 4px 8px 0 0;
color: #1572B6;
font-weight: 700;
}
/* Drop cap effect — classic magazine-style opening letter */
::placeholder and ::selection
/* ::placeholder — styles the placeholder text of an input */
input::placeholder,
textarea::placeholder {
color: #aaa;
font-style: italic;
font-size: 0.9em;
}
/* ::selection — styles the highlighted (selected) text */
::selection {
background: #1572B6;
color: #ffffff;
}
/* Per-element selection color */
.code-block::selection,
.code-block *::selection {
background: #264f78;
color: #ffffff;
}
::marker
Styles the bullet or number of a list item — no need to remove the default bullet and add your own with ::before anymore.
/* Style list bullets */
li::marker {
color: #1572B6;
font-size: 1.2em;
}
/* Custom content for ordered lists */
ol li::marker {
color: #e44d26;
font-weight: 700;
}
/* Emoji bullets */
ul.checklist li::marker {
content: "✓ ";
color: #2e7d32;
}
::backdrop
Styles the full-viewport backdrop that appears behind modal dialogs, fullscreen elements, and popover elements.
/* Style the backdrop of a
📋 Summary
- ::before / ::after — virtual nodes inserted inside the element. Require
content:. Use for decorations, tooltips, clearfix, badges. - content: attr(data-x) — reads HTML attribute value into generated content.
- ::first-line / ::first-letter — style the first rendered line or first character of a block. Limited property support.
- ::placeholder — style input placeholder text: color, font-style, font-size.
- ::selection — change highlight color when user selects text.
- ::marker — style list item bullets/numbers directly, including
content:for emoji bullets. - ::backdrop — style the overlay behind
<dialog>or fullscreen elements. - Double colon (
::) is required in modern CSS. Single colon (:) still works for legacy reasons but avoid it for new code.
Frequently Asked Questions
The content property is what makes the pseudo-element exist in the render tree. Without it, the browser does not generate the pseudo-element box at all — it's as if the rule doesn't exist. For decorative uses (shapes, dividers), set content: "" — an empty string still generates the box. For text, set content: "your text". You can also use content: attr(data-attribute) to pull text from an HTML attribute.
No — pseudo-elements are not part of the DOM. They exist only in the CSS render tree, so JavaScript cannot select them with querySelector or add event listeners. Clicks on a pseudo-element area are received by the real element, not the pseudo-element itself. If you need a clickable element, add a real DOM node.
A pseudo-class (single colon, e.g. :hover) selects a real element in a particular state. A pseudo-element (double colon, e.g. ::before) either targets a sub-part of an element's rendering (like ::first-letter) or creates a virtual element that doesn't exist in the HTML (like ::before and ::after). There is also a practical distinction: you can have multiple pseudo-classes stacked on one element, but only one pseudo-element per selector chain.