W3docs

CSS ::before Pseudo Element

Use the ::before CSS pseudo-element for adding elements before the content. Read about the pseudo-element and try examples.

The CSS ::before pseudo-element creates a generated element that is inserted as the first child of the element you target, before its real content. It is one of the two "generated content" pseudo-elements (its mirror is ::after), and it is most often used to add decorative icons, labels, counters, quotation marks, or visual flourishes without touching the HTML.

This page covers what ::before does, the one property it cannot live without, runnable examples, the most common real-world patterns, and the accessibility gotchas you need to know.

How ::before works

A ::before pseudo-element only renders when you also declare the content property — that value is what gets inserted. Without content, nothing appears at all (not even an empty box).

Key behaviors:

  • Inline by default. Like a <span>, it sits inline with the surrounding text until you change its display (for example to inline-block or block).
  • It is a real box. You can style, animate, position, or float it like any other element, and it inherits styles from the element it belongs to.
  • It comes first. ::before is inserted before the element's content; ::after is inserted after it. Both live inside the element, between its tags.
  • Single-colon still works. The legacy :before syntax (one colon) is equivalent and is what very old browsers understood. The double-colon ::before is the modern standard that distinguishes pseudo-elements from pseudo-classes — prefer it.
Info

::before and ::after do not work on replaced elements such as <br>, <img>, <input>, or <video>, because those elements have no document content to insert generated content around.

Syntax

selector::before {
  content: "value"; /* required */
  /* other declarations */
}

The content value can be a literal string, an image (url(...)), an attribute value (attr(...)), or a counter (used together with counter-increment). For a purely decorative box with no text, use an empty string: content: "".

Examples

Insert a text label before content

Here ::before prepends a fixed string to every paragraph:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      p::before { 
        content: "  William Shakespeare -";
      }
    </style>
  </head>
  <body>
    <h2>::before selector example</h2>
    <p>"Be or not to be".</p>
  </body>
</html>

The inserted text "William Shakespeare -" appears directly in front of the quote, even though it exists nowhere in the HTML.

Style the generated box

Because the pseudo-element is a box, you can give it a background, border, and display value just like a normal element:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      p::before { 
        content: "William Shakespeare-";
        display: inline-block;
        background-color: #ccc;
        color: #666;
        border: 2px dotted #000;
      }
    </style>
  </head>
  <body>
    <h2>::before selector example</h2>
    <p>"Be or not to be".</p>
  </body>
</html>

Common use cases

::before shines whenever you need decoration that does not belong in the markup:

  • Icons and bullets — prepend a symbol (content: "★") or an url() image to links, list items, or buttons.
  • Required-field markers — add a red asterisk to labels: label.required::before { content: "*"; color: red; }.
  • Opening quotation marks — wrap blockquotes with typographic quotes.
  • Counters — combine with counter-increment to number sections automatically.
  • Pull values from attributes — display an element's own attribute with attr():
abbr[title]::before {
  content: attr(title) ": ";
  font-weight: bold;
}

Accessibility and gotchas

  • content is mandatory. If you forget it, the pseudo-element is not generated at all.
  • Decorative boxes need content: "". For a purely visual element (a divider, an icon background) set an empty string so the box still renders.
  • Generated text is not selectable and most screen readers either ignore it or read it inconsistently. Never put information the user must have (like critical instructions) only in ::before.
  • It does not apply to replaced elements (<img>, <input>, <br>, etc.).
  • Insertion point matters. ::before is the first child inside the element — not before the element's opening tag.
Note

For purely decorative pseudo-elements, always set content: '' to ensure they render correctly across all browsers.

Browser support

::before is supported in all modern browsers. The single-colon form (:before) is also widely supported and was the syntax used before CSS3, so use it only if you must support very old browsers.

  • ::after — insert content after an element.
  • content — the property that defines what ::before inserts.
  • counter-increment — build automatic numbering with generated content.
  • position — place a generated element precisely.

Practice

Practice
What does the '::before' pseudo-element do in CSS?
What does the '::before' pseudo-element do in CSS?
Was this page helpful?