::before and ::after in CSS: injecting content without touching the HTML

::before and ::after add generated content before or after an element, for icons, counters, or a clearfix, without changing the HTML.
4 min read
Believemy logo

Two pseudo-elements show up almost everywhere in modern stylesheets: ::before and ::after. They add a rendered fragment right before or right after an element's real content, without ever touching the HTML.

Decorative icons, list counters, the old-school clearfix, or tooltips built entirely in CSS: these two pseudo-elements cover an impressive range of needs for a tool that looks so simple on the surface.


Definition

::before inserts generated content right before an element's real content, inside its box. ::after inserts that content right after. In both cases, that content does not exist in the HTML: it is entirely produced by CSS at render time.


The one requirement: content

Without the content property, neither pseudo-element shows up, even if every other property is correctly set. An empty value is enough to make the generated box exist.

CSS
/* decorative icon before a badge */
.badge::before {
  content: "★";
  margin-right: 4px;
  color: gold;
}

/* old-school clearfix after a container */
.container::after {
  content: "";
  display: table;
  clear: both;
}

/* automatic counter inside a list */
.steps {
  counter-reset: step;
}
.steps li::before {
  counter-increment: step;
  content: "Step " counter(step) ": ";
  font-weight: bold;
}

The third example shows a lesser known use: ::before can display a native CSS counter, incremented automatically for every item in the list, without hardcoding a single number in the HTML.


Common use cases

The clearfix, an older technique still found in existing code, uses ::after to force a container to wrap elements set to float. Pure CSS tooltips combine ::after with a parent element's :hover state to display text on hover, with no dependency on JavaScript. Decorative icons avoid adding an extra tag just for a purely visual symbol.

UsePseudo-element
Icon before a piece of text::before
Arrow or symbol after a link::after
Clearfix::after
Automatic counter::before
Good to knowContent injected by ::before or ::after is never read consistently by every screen reader, and it cannot be selected by a user. Save these pseudo-elements for decoration, never for information essential to understanding.


Building a tooltip in pure CSS

A tooltip that appears on hover nicely illustrates how ::after pairs with a Pseudo-class like :hover. The pseudo-element supplies the text to display through content, and the pseudo-class controls its visibility based on the parent element's hover state, with no JavaScript needed for this behavior even though it looks dynamic.

CSS
.tooltip {
  position: relative;
}
.tooltip::after {
  content: attr(data-text);
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}
.tooltip:hover::after {
  opacity: 1;
}

The attr() function reads the value of a data-* attribute directly from the HTML, which makes it possible to reuse the same CSS block for any tooltip text, simply by changing the attribute's value on each relevant element.


Frequently asked questions

QuestionCan an image be placed inside ::before?

Yes, through content: url("image.png"), or more often by leaving content empty and applying a background-image to the pseudo-element instead, for more control over its size and position. This second method also makes it easier to use background-size and background-position to fine-tune the final rendering based on the generated box's dimensions.

QuestionDo ::before and ::after work on any tag?

No, they do not apply to so-called replaced elements, such as img or input, since these tags have no internal content to insert anything into.

QuestionCan the content text include quotes or apostrophes?

Yes, as long as they are escaped properly or the other quote type is used to wrap the value, for example content: "the example's" with double quotes around a single apostrophe. In practice, it is often simpler to consistently wrap the value in double quotes, escaping a lone apostrophe with a backslash when needed.

Related terms

Discover our hTML and CSS glossary

Browse the terms and definitions most commonly used in HTML and CSS development.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.