ESC

Type to search the knowledge base.

Pseudo-elements Before After

::before and ::after generate children for decoration — required content/display, accessibility limits, and practical UI patterns.

beginner3 min read
  • css
  • pseudo-elements

::before and ::after create generated children inside an element’s box. They’re ideal for decorative lines, icons, badges, and clearfix-era hacks — not for meaningful content that belongs in HTML.

Docs: MDN ::before, ::after, pseudo-elements.

Minimum viable pseudo-element

.button::before {
  content: ""; /* required — without content, box often doesn’t generate */
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  margin-inline-end: 0.4rem;
  border-radius: 50%;
  background: currentColor;
}

Rules of thumb:

  1. content is required (even "") for ::before/::after to generate a box.
  2. Treat them like children for flex/grid — they become items if the parent is flex/grid.
  3. Single colon :before is the old CSS2 syntax; prefer :: for pseudo-elements.

Decorative patterns

Gradient underline

.link-fancy {
  position: relative;
  text-decoration: none;
}

.link-fancy::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: -0.15em;
  height: 2px;
  background: linear-gradient(90deg, var(--brand), transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 150ms ease;
}

.link-fancy:hover::after,
.link-fancy:focus-visible::after {
  transform: scaleX(1);
}

Quote mark

blockquote::before {
  content: "“";
  font-size: 3rem;
  line-height: 1;
  color: var(--brand);
  float: left;
  margin-inline-end: 0.25rem;
}

Prefer real typography/HTML for multilingual quotes when accuracy matters.

Badge count (careful)

.icon-btn[data-count]::after {
  content: attr(data-count);
  position: absolute;
  /* … */
}

attr() in content is fine for decorative counts; screen readers may not announce it as a live status — put the real number in accessible text or aria-label on the control.

Flex/grid participation

.cluster {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.cluster::before {
  content: "";
  width: 4px;
  align-self: stretch;
  background: var(--brand);
}

Generated boxes count toward layout — surprising gaps and alignment often trace to forgotten pseudo-elements.

What not to put in content

  • Critical instructions (“Click save or lose data”)
  • Form labels
  • SEO text you expect crawlers to treat as primary content
  • Interactive hit targets (can’t host real buttons)

Screen reader treatment of content strings is inconsistent; assume decorative unless proven otherwise with testing.

Other pseudo-elements (map)

Pseudo-element Use
::placeholder Input placeholder styling
::selection Highlight colors
::marker List markers
::first-line / ::first-letter Typographic flourish

Interview out-loud

“::before and ::after insert generated children. They need content, can participate in flex/grid, and should be decorative. Meaningful text stays in the DOM for accessibility. I use them for icons, underlines, and visual badges, with accessible names on the real controls.”

Footguns

  1. Missing content — “why isn’t my ::after showing?”
  2. Putting required text only in content.
  3. position: absolute without positioned parent.
  4. Animating huge pseudo-elements with filters on many nodes.
  5. Confusing pseudo-classes (:hover) with pseudo-elements (::before).

Required indicator pattern

.label--required::after {
  content: " *";
  color: var(--danger);
}
.label--required::after {
  /* Better: aria-hidden decorative star with text alternative in the label */
}

Prefer including “(required)” in the accessible name or aria-required on the control. Decorative stars alone fail some users. If you use ::after for the star, keep the word “required” available to AT via the label text or aria-describedby.

Empty states

.list:empty::before {
  content: "No items yet.";
  color: var(--text-muted);
}

Handy, but screen readers may ignore pure CSS content — consider a real DOM empty state for critical UX.

Further reading

Related guides