Layering with ::before and ::after
::before and ::after create generated boxes as the first and last child of an element. They are ideal for decoration that belongs to a component but should not become extra document content: glows, badges, borders, overlays, and animated fills.
Generated content still participates in layout, painting, and stacking. Reliable pseudo-elements therefore need an explicit content value, a positioning context, and deliberate rules for clipping and pointer events.
Create and position the generated box
A pseudo-element is not rendered until content creates it. For purely visual layers, use content: "". Give the parent position: relative and the pseudo-element position: absolute; inset: 0 then covers the parent's padding box.
Use pointer-events: none on decoration placed above interactive content. Without it, a transparent overlay can intercept clicks even though visitors cannot see the box.
- content
- Required for
::beforeand::afterto generate a box. Keep meaningful text in HTML. - inset
- A compact way to set top, right, bottom, and left for absolutely positioned layers.
- isolation
- Creates a local stacking context so negative layers do not disappear behind unrelated ancestors.
.panel {
position: relative;
isolation: isolate;
overflow: hidden;
border-radius: 1rem;
}
.panel::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
border-radius: inherit;
background: linear-gradient(135deg, #2563eb, #a855f7);
pointer-events: none;
}Control stacking without surprises
A negative z-index can place a pseudo-element behind its parent, but it may also slip behind an ancestor background. isolation: isolate on the component creates a local stacking context and makes that pattern predictable.
When content must remain above an overlay, position the content wrapper and give it a higher stacking level. Avoid arbitrary values such as 9999; a small local scale is easier to reason about.
Animate borders, fills, and underlines
Because a pseudo-element has its own transform and opacity, it can animate without changing the component's box. A link underline can grow with scaleX, while a button fill can slide under the label using translateX.
Inherit the parent's border-radius whenever the layer reaches an edge. Otherwise colored corners can extend beyond the rounded surface.
.link { position: relative; }
.link::after {
content: "";
position: absolute;
left: 0; right: 0; bottom: -.2em;
height: 2px;
background: currentColor;
transform: scaleX(0);
transform-origin: right;
transition: transform 180ms ease;
}
.link:hover::after,
.link:focus-visible::after {
transform: scaleX(1);
transform-origin: left;
}Keep semantics in the document
Generated content is not a dependable accessibility API. Do not use it for instructions, prices, status messages, or information required to understand an action. Put meaningful content in HTML and reserve pseudo-elements for visual reinforcement.
Pseudo-elements are also unavailable or inconsistent on replaced elements such as img and many form controls. Wrap those elements when you need an extra visual layer.
Live catalog examples
These production examples use ::before / ::after. Open any effect to inspect its complete source and experiment in the browser editor.
Browser support
Support notes refer to stable, unprefixed behavior unless a prefix is explicitly listed.
| Feature | Browsers | Note |
|---|---|---|
| ::before / ::after | All modern browsers | Requires `content` to generate the pseudo-element. |
| inset | All modern browsers | Use physical offsets only when supporting much older browsers. |
| isolation | All modern browsers | Useful for containing blend modes and negative stacking. |
Common pitfalls
The content declaration is missing
Add
content: ""for a decorative generated box.A negative layer disappears
Create a local stacking context with
isolation: isolateand keep z-index values local.The overlay blocks interaction
Set
pointer-events: noneunless the pseudo-element intentionally handles input.Rounded corners leak
Use
border-radius: inheritor clip the component when the layer reaches its edges.
Frequently asked questions
- Do pseudo-elements add DOM nodes?
- No. They create boxes in the formatting tree, but they are not ordinary HTML elements.
- Can I use both on one element?
- Yes. They provide two independent generated layers, each with its own layout and stacking rules.
- Why does ::before not appear on an image?
- Images are replaced elements. Wrap the image and place the pseudo-element on the wrapper.
- Can generated content be accessible?
- Support varies. Keep essential text and state in semantic HTML.
Related guides
- :hoverInteraction effects with :hover and transitionsDesign responsive hover feedback that also works for keyboards, touch input, and reduced-motion users.
- @keyframesCSS animations with @keyframesBuild reliable CSS animation timelines, combine multiple motions, and keep them smooth and accessible.
- clip-pathCutting shapes with clip-pathClip boxes into responsive geometric shapes and animate them without changing document layout.
- maskAlpha masking with CSS maskControl visibility per pixel with gradients and images, including soft edges, real cutouts, and reusable monochrome icons.
Last updated:
All guides