CSS · Selectors & Effects

Pseudo-Elements

Pseudo-elements let you style a part of an element, or add decoration, without touching the HTML: a drop cap, an icon before a link, a custom bullet.

Intermediate 5 min Lesson 16 of 26 Runnable examples
Before you start:Pseudo-Classes
0/26 in CSS
On this page · 5 min · Intermediate

Learning objectives#

  • Add decorations with ::before and ::after
  • Style parts of text with ::first-letter and ::first-line
  • Style placeholders, selections and list markers
  • Know when content belongs in HTML instead

Explanation#

Pseudo-elements use two colons: p::first-line. They target something that is not a real element in the HTML.

::before and ::after insert a box as the first or last child of an element. They need content: "" to appear, even if empty.

::first-letter styles the first letter (drop caps); ::first-line styles the first line, whatever its length.

::placeholder styles input hint text; ::selection styles highlighted text; ::marker styles list bullets and numbers.

Content added with ::before/::after is decoration. Screen readers may or may not read it, and users cannot copy it — keep real information in HTML.

Code example: Decorations without extra HTML#

HTMLDecorations without extra HTML Runnable
<style>
  body { font-family: Georgia, serif; max-width: 60ch; }
  .story::first-letter { float: left; font-size: 3.2em; line-height: 1; padding-right: 6px; color: #b45309; }
  .story::first-line { font-variant: small-caps; }


  .required::after { content: " *"; color: #dc2626; }
  a[href^="http"]::after { content: " ↗"; font-size: 0.8em; }


  .quote { position: relative; padding-left: 28px; font-style: italic; }
  .quote::before { content: "“"; position: absolute; left: 0; top: -12px; font-size: 3rem; color: #94a3b8; }


  ul.ticks li::marker { content: "✓  "; color: #16a34a; }
  ::selection { background: #fde68a; }
  input::placeholder { color: #94a3b8; font-style: italic; }
</style>


<p class="story">Once upon a time in a small village by the river, there lived a potter who made the most beautiful lamps in the land.</p>
<label class="required">Email</label> <input placeholder="you@example.com">
<p>Read more on <a href="https://developer.mozilla.org">MDN</a>.</p>
<p class="quote">Simplicity is the soul of efficiency.</p>
<ul class="ticks"><li>Fast</li><li>Accessible</li></ul>
Expected output
A story with a large orange drop cap and small-caps first line, a red asterisk after “Email”, an arrow after the external link, a big decorative quote mark, green tick bullets and yellow text selection.
Opens this example in the full playground

Step-by-step explanation#

  1. ::first-letter floats a large first letter for a classic drop cap.
  2. .required::after adds a red asterisk without editing every label.
  3. a[href^="http"]::after marks external links automatically.
  4. .quote::before draws a decorative quote mark positioned in the padding.
  5. ::marker replaces the default bullets with ticks.
  6. ::selection changes the highlight colour when text is selected.

Real-world use case#

Pseudo-elements build tooltips, ribbons, custom checkbox shapes, overlay gradients on images and decorative underlines — all without cluttering the HTML.

Common mistakes#

Forgetting content

::before and ::after render nothing without a content property. Use content: "" for purely visual shapes.

::before on <img> or <input>

Void/replaced elements have no children, so ::before and ::after do not work on them. Wrap them instead.

Putting important text in content

Prices or instructions in CSS content cannot be selected and may be skipped by assistive technology.

Best practices#

  • Use pseudo-elements for decoration only
  • Use content: "" with width/height for shapes
  • Use two colons for pseudo-elements, one for pseudo-classes
  • Remember ::before/::after are children — position: relative on the parent helps place them

Remember this#

Two colons = a “ghost” part of the element.

No content, no show — ::before/::after need content.

Decoration in CSS, information in HTML.

Practice exercise#

Your task: Add a small grey “#” before every h2, without changing the HTML.

Need a hint?
h2::before with content and colour.
Show solution
CSS Illustrative
h2::before {
  content: "# ";
  color: #94a3b8;
}

Mini quiz#

Pseudo-Elements quizMultiple choice Question 1 of 3

What is required for ::after to appear?

Score so far: 0/0

Want more? Practise all CSS MCQs · CSS interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.