All articles
CSS Fundamentals

CSS ::before and ::after: The Complete Practical Guide

18 November 2024 8 min read CSS Fundamentals

Master CSS pseudo-elements for decorative lines, badges, tooltips, custom list markers, overlay effects and more. Includes 10 real UI patterns you can drop into any project.

CSS pseudo-elements are one of those features that separate developers who write a lot of HTML from those who write very little. ::before and ::after let you attach styled content to an element without touching the markup.

The basics

Every element has two pseudo-elements available: ::before (inserted before the content) and ::after (inserted after). They require a content property to exist:

.badge::after {
  content: 'New';
  background: #e8a020;
  color: #000;
  font-size: 10px;
  padding: 2px 6px;
  border-radius: 100px;
  margin-left: 8px;
  vertical-align: middle;
}

content can be a string, empty string (""), attr(), or a counter. For decorative shapes, use an empty string and position absolutely.

Pattern 1 — Decorative underlines
.section-title {
  position: relative;
  display: inline-block;
}
.section-title::after {
  content: '';
  position: absolute;
  bottom: -6px;
  left: 0;
  width: 40px;
  height: 3px;
  background: var(--accent);
  border-radius: 2px;
}
Pattern 2 — Overlay on hover
.card {
  position: relative;
  overflow: hidden;
}
.card::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(232,160,32,0.15);
  opacity: 0;
  transition: opacity 0.2s;
  z-index: 1;
}
.card:hover::before { opacity: 1; }
Pattern 3 — Quotation marks
blockquote {
  position: relative;
  padding: 16px 24px 16px 48px;
}
blockquote::before {
  content: 'C'; /* opening double quote */
  position: absolute;
  left: 8px;
  top: 0;
  font-size: 64px;
  line-height: 1;
  color: var(--accent);
  font-family: Georgia, serif;
  opacity: 0.6;
}
Pattern 4 — Tooltip
[data-tooltip] { position: relative; }

[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 10px;
  font-size: 12px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
}
[data-tooltip]:hover::after { opacity: 1; }

The attr(data-tooltip) function pulls the content directly from the HTML attribute — no JavaScript needed for simple tooltips.