CSS pseudo-elements ::before and ::after let you insert content into the page without adding HTML. They produce virtual elements you can style like real ones, but they live in the CSS layer. No DOM nodes, no JavaScript, no cluttered markup.
They are the workhorses of decorative design. Custom bullets, underlines, tooltip arrows, quote marks, badges, overlays, and clearfixes all sit on ::before and ::after. Once you know how they work, you find uses for them constantly.
The one rule that catches everyone: both pseudo-elements need a content property. Even when you want pure decoration (a colored block, a border, a shape), you still write content: ''. Without it, the pseudo-element does not render.
The Basics: How ::before and ::after Work
Every HTML element can have two pseudo-elements attached to it. ::before inserts content before the element's actual content. ::after inserts content after it. Both are inline by default but can be changed to any display type.
`css
.quote::before {
content: '"';
font-size: 2em;
color: #3b82f6;
margin-right: 4px;
}
.quote::after {
content: '"';
font-size: 2em;
color: #3b82f6;
margin-left: 4px;
}
`
This adds styled quotation marks around any element with the class quote without touching the HTML.
Important things to know:
- Pseudo-elements do not exist in the DOM. You cannot select them with JavaScript using
querySelector. - They inherit styles from their parent element (font, color, line-height).
- Self-closing elements like
,, andcannot have pseudo-elements because they cannot contain content. - Use the double colon syntax (
::before) for pseudo-elements and single colon (:hover) for pseudo-classes. Browsers accept single colon for backward compatibility, but double colon is the correct modern syntax. - The
contentproperty accepts strings,attr()function values, counters, URLs, and empty strings.

Decorative Effects Without Extra HTML
The most common use of pseudo-elements is adding visual decoration that does not belong in the HTML.
Custom underlines:
`css
.fancy-link::after {
content: '';
display: block;
width: 100%;
height: 2px;
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
transform: scaleX(0);
transition: transform 0.3s ease;
}
.fancy-link:hover::after {
transform: scaleX(1);
}
`
Section dividers:
`css
.section::after {
content: '';
display: block;
width: 60px;
height: 3px;
background: #3b82f6;
margin: 24px auto 0;
}
`
Card ribbon badges:
`css
.card::before {
content: 'NEW';
position: absolute;
top: 12px;
right: -6px;
background: #ef4444;
color: white;
padding: 4px 12px;
font-size: 12px;
font-weight: 700;
}
`
These patterns keep your HTML clean. The decoration lives in CSS where it belongs, making it easy to change or remove without editing markup. After building your styles, run them through the CSS Minifier to reduce file size for production.
The most common use of pseudo-elements is adding visual decoration that does not belong in the HTML.
Positioning and Layout Tricks
Pseudo-elements become truly powerful when combined with absolute positioning. By setting the parent to position: relative and the pseudo-element to position: absolute, you can place decorative content anywhere relative to the parent.
Overlay on images:
`css
.image-container {
position: relative;
}
.image-container::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(0,0,0,0.6), transparent);
pointer-events: none;
}
`
This creates a dark gradient overlay from the bottom of the image, perfect for placing text on top of photos.
Tooltip arrows:
`css
.tooltip::after {
content: '';
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
border-width: 8px;
border-style: solid;
border-color: #1f2937 transparent transparent transparent;
}
`
The triangle arrow is created entirely with CSS borders. No images, no SVGs, no extra elements.
Aspect ratio boxes (for older browser support):
`css
.aspect-16-9::before {
content: '';
display: block;
padding-top: 56.25%;
}
`
Modern CSS has the aspect-ratio property, but this pseudo-element technique still works everywhere and is useful when you need broader compatibility.
Using attr() and CSS Counters with Pseudo-Elements
The content property can pull values from HTML attributes using the attr() function. This bridges the gap between HTML data and CSS presentation.
`css
a[href^="http"]::after {
content: ' (' attr(href) ')';
font-size: 0.8em;
color: #6b7280;
}
`
This displays the URL after every external link. Useful for print stylesheets where users cannot click links.
Data attribute tooltips:
`css
[data-tooltip]::before {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #1f2937;
color: white;
padding: 6px 12px;
border-radius: 4px;
font-size: 14px;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s;
}
[data-tooltip]:hover::before {
opacity: 1;
}
`
CSS counters are another powerful feature that works with pseudo-elements:
`css
ol.custom-list {
counter-reset: item;
list-style: none;
}
ol.custom-list li::before {
counter-increment: item;
content: counter(item) '. ';
font-weight: 700;
color: #3b82f6;
}
`
This creates a numbered list with custom styling on the numbers, something you cannot achieve with default list styles. Format your final code with the Code Formatter to keep it clean and consistent.

Accessibility Considerations
Pseudo-element content is announced by some screen readers but not all. This inconsistency means you should never put important information in pseudo-elements. If a user needs to understand the content to use your page, it belongs in real HTML.
Good uses of pseudo-elements (decorative, non-essential): - Visual separators and dividers - Decorative quotes and icons - Hover effects and animations - Background patterns and overlays
Bad uses (content carries meaning): - Required field indicators (the asterisk *) without an accessible label - Error messages or status indicators - Navigation icons without text alternatives - Content that conveys information not available elsewhere on the page
When you use pseudo-elements for icons or indicators, make sure the actual meaning is communicated through real HTML or ARIA attributes. A red asterisk from ::after is fine if the form field also has aria-required="true".
For purely decorative pseudo-elements, the browser typically ignores them for accessibility purposes, which is the correct behavior. Do not add role="presentation" or aria-hidden to pseudo-elements because they are not real DOM nodes and cannot have attributes.
Minify your final HTML with the HTML Minifier after implementing pseudo-element patterns. Cleaner HTML makes it easier to audit what is real content versus what the CSS generates.
FAQ
Can I use ::before and ::after on input elements?
No. Input elements are replaced or void elements that cannot contain content, so pseudo-elements do not work on them. The common workaround is to wrap the input in a span or div and apply the pseudo-elements to the wrapper instead.
How many pseudo-elements can an element have?
Each element can have exactly one ::before and one ::after pseudo-element, for a maximum of two. If you need more, nest additional elements in your HTML or use other techniques like box shadows or gradients.
Do pseudo-elements affect layout and box model?
Yes. Pseudo-elements are rendered as children of their parent and participate in the normal layout flow. They have their own box model (margin, padding, border, width, height) and can affect the size and position of surrounding content. This is why display: block or position: absolute is commonly used to control their impact on layout.
Can I animate pseudo-elements?
Yes. Pseudo-elements support CSS transitions and animations just like regular elements. You can animate their opacity, transform, background, width, height, and most other properties. Use transition for hover effects and @keyframes for continuous animations.
### Can I use ::before and ::after on input elements.
Markdown Table Generator: Build Clean Tables Without the Pain
Markdown tables are simple until the pipes and dashes stop lining up. Learn the syntax, alignment tricks, and a free tool that formats tables for you.
CSV to JSON: Convert Spreadsheet Data for APIs and Code
Turn a CSV export into clean JSON for APIs, imports, and scripts. Learn how the conversion works, common pitfalls with types and quotes, and a free tool.
JSON Guide: Format, Validate, and Convert JSON Files
JSON guide for developers: syntax rules, common parse errors, formatting and schema validation, plus how to convert between JSON and CSV files.
