Pseudo Elements in CSS

Pseudo elements in CSS style a specific part of an element or create a virtual part that is not written directly in the HTML. They are written with a double colon, such as ::before, ::after, ::first-line, and ::selection. They are useful for decoration, generated content, custom bullets, highlighted text, placeholders, and small interface details.

Pseudo elements are different from pseudo classes. A pseudo class selects an element in a certain state, like :hover or :focus. A pseudo element targets a part of the element, or creates a generated part before or after its real content.

Basic Pseudo Element Syntax

The modern syntax uses two colons. Older CSS allowed one colon for some pseudo elements, but the double colon form is clearer because it separates pseudo elements from pseudo classes.

p::first-line {
  font-weight: 700;
}

.badge::before {
  content: "New";
}

The first rule styles the first formatted line of a paragraph. The second rule creates generated content before the real content of a badge element.

::before and ::after

The most common pseudo elements are ::before and ::after. They create generated inline boxes before or after the element content. They need the content property to appear.

.link::after {
  content: " ->";
}

.required::after {
  content: " *";
  color: #dc2626;
}

This is useful for decorative symbols, required field marks, small labels, icons, and visual hints. If the content is important for understanding, do not rely only on generated content because assistive technology behavior can vary.

The content Property

The content property controls what ::before and ::after generate. It can be an empty string, text, an attribute value, a counter, or an image.

a::after {
  content: " (" attr(href) ")";
}

This can reveal link URLs in print styles. Attribute-based content is useful, but it should be used carefully because generated content can become noisy.

Decorative Shapes

Pseudo elements are often used to create decorative shapes without extra markup. A card can have a small accent bar, a button can have a shine effect, or a heading can have a line behind it.

.card {
  position: relative;
}

.card::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 4px;
  background: #2563eb;
}

The HTML stays clean because the accent bar is only decoration. This is a good use of pseudo elements.

Overlay Effects

Pseudo elements can create overlays when the parent is positioned. This is common for image cards, hero sections, and hover effects.

.hero {
  position: relative;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.35);
}

The overlay sits on top of the hero background. If the hero contains text, control stacking with z-index so the text stays above the overlay.

::first-line and ::first-letter

The ::first-line pseudo element styles the first formatted line of text. The ::first-letter pseudo element styles the first letter. These are useful for editorial typography.

.article-intro::first-line {
  font-weight: 700;
}

.article-intro::first-letter {
  font-size: 3rem;
  float: left;
  line-height: 1;
}

Use these carefully. Large drop caps can look good in long-form content, but they can also reduce readability if the layout is cramped.

::selection

The ::selection pseudo element styles text selected by the user.

::selection {
  background: #fde68a;
  color: #111827;
}

Selection styles should keep strong contrast. Avoid making selected text harder to read just for branding.

::placeholder

The ::placeholder pseudo element styles placeholder text in inputs and textareas.

input::placeholder {
  color: #9ca3af;
}

Placeholder text should not replace labels. It is temporary hint text and disappears when the user types.

::marker

The ::marker pseudo element styles the marker of list items, such as bullets or numbers.

li::marker {
  color: #2563eb;
  font-weight: 700;
}

This is cleaner than using custom spans or background images for simple list marker styling.

::file-selector-button

The ::file-selector-button pseudo element styles the button part of a file input.

input[type="file"]::file-selector-button {
  border: 0;
  border-radius: 6px;
  padding: 0.65rem 1rem;
  background: #2563eb;
  color: white;
}

This makes file inputs easier to match with the rest of a design system while keeping the native input behavior.

Accessibility Rules

Use pseudo elements mostly for decoration or duplicated helper text. Do not place critical information only in content. If a message is essential, put it in the HTML so it is available to screen readers, copy tools, translation tools, and search engines.

Pseudo elements are excellent for visual polish. They should not become a hidden content system.

Pseudo Elements and pointer-events

Decorative pseudo elements can accidentally sit on top of real links or buttons. If a generated overlay is blocking clicks, use pointer-events: none on the pseudo element.

.button {
  position: relative;
}

.button::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
}

This lets the visual layer exist without stealing mouse or touch interaction from the real element. It is especially useful for shine effects, overlays, and decorative borders.

Using Counters with Pseudo Elements

Pseudo elements can display CSS counters. This is useful for custom numbered lists, steps, timelines, and documentation sections.

.steps {
  counter-reset: step;
}

.step::before {
  counter-increment: step;
  content: counter(step);
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: #2563eb;
  color: white;
}

The number is generated by CSS, while the actual step content remains in HTML. This keeps markup cleaner for visual numbering patterns.

Print Styles with Pseudo Elements

Pseudo elements can be useful in print styles. For example, printed links can show their destination URL after the visible link text.

@media print {
  a[href]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
  }
}

This helps printed documents remain useful because the reader can still see where a link points. It is a practical generated-content use case because printed pages cannot preserve clickable links.

Debugging Pseudo Elements

Browser developer tools can inspect pseudo elements. If one is not visible, check the content property, display value, size, color, stacking order, and whether it is hidden behind another layer.

  • Check content on before and after.
  • Check position and z-index for overlays.
  • Check width and height for empty decorative shapes.
  • Check pointer-events if clicks are blocked.
  • Check contrast for generated labels and markers.
  • Check whether the pseudo element is attached to the correct selector.

::backdrop

The ::backdrop pseudo element styles the backdrop behind elements such as native dialogs when they are opened modally.

dialog::backdrop {
  background: rgb(15 23 42 / 0.65);
  backdrop-filter: blur(4px);
}

This is useful for modal dialogs because the background layer can be styled without adding another overlay element in the HTML.

Pseudo Elements in Buttons

Buttons often use pseudo elements for small decorative effects such as background slides, loading rings, or icon layers. The real button text should remain in HTML, while the pseudo element handles the visual effect.

.button {
  position: relative;
  overflow: hidden;
}

.button::before {
  content: "";
  position: absolute;
  inset: 0;
  translate: -100% 0;
  background: rgb(255 255 255 / 0.18);
  transition: translate 180ms ease;
}

.button:hover::before {
  translate: 0 0;
}

This creates a sliding highlight effect while keeping the button markup simple. Because it is decorative, the pseudo element does not need semantic meaning.

Generated Content Limitations

Generated content is not a replacement for real content. It may not be copied with text selection, translated reliably, indexed as normal content, or announced consistently by assistive technologies. Use it for decoration, labels that duplicate existing meaning, or print helpers.

If users must read, copy, search, or interact with the content, put it in HTML. CSS should enhance presentation, not hide important information inside stylesheets.

Layering Pseudo Elements

A single element can have both ::before and ::after. This allows two decorative layers without extra markup, such as a background glow and foreground line.

.title {
  position: relative;
  isolation: isolate;
}

.title::before {
  content: "";
  position: absolute;
  inset: auto 0 -0.2em;
  height: 0.35em;
  background: #bfdbfe;
  z-index: -1;
}

The isolation property can help keep negative z-index decoration inside the component context instead of slipping behind unrelated page layers.

When Not to Use Pseudo Elements

Do not use pseudo elements when the content needs to be edited by a content writer, translated, searched, copied, or announced as essential information. In those cases, normal HTML is the better place for the content.

Also avoid complex pseudo element tricks when a simple extra element would be clearer. Clean HTML matters, but overly clever CSS can become harder to maintain than one meaningful wrapper or span.

Pseudo Elements in Layout

Generated pseudo elements can participate in flex and grid layouts if they are generated as boxes. This can be useful for separators or decorative elements inside a component.

.meta {
  display: flex;
  gap: 0.5rem;
}

.meta::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: #22c55e;
  align-self: center;
}

The dot is decorative and aligns with the text without requiring extra markup.

Maintainable Pseudo Elements

Keep pseudo element rules close to the component they support. If a pseudo element needs many unrelated properties, ask whether the visual effect is worth the complexity. Good pseudo element code should make the HTML cleaner without making the CSS mysterious.

When the effect becomes hard to explain, simplify it.

Readable CSS wins.

Common Pseudo Element Mistakes

  • Forgetting the content property on before and after.
  • Using generated content for important information.
  • Confusing pseudo elements with pseudo classes.
  • Forgetting positioning and z-index when creating overlays.
  • Making selection colors low contrast.
  • Adding decorative pseudo elements that block clicks.

Pseudo Elements in CSS FAQ

What is a pseudo element in CSS?

A pseudo element styles a specific part of an element or creates generated content before or after it.

What is the difference between before and after?

::before inserts generated content before the element content, while ::after inserts it after the element content.

Why is ::before not showing?

Usually the content property is missing, or the generated element has no visible size or style.

Should I use one colon or two colons?

Use the modern double-colon syntax for pseudo elements.


Continue learning CSS in order
Follow the topic sequence with the previous and next lesson.