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 itsdisplay(for example toinline-blockorblock). - 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.
::beforeis inserted before the element's content;::afteris inserted after it. Both live inside the element, between its tags. - Single-colon still works. The legacy
:beforesyntax (one colon) is equivalent and is what very old browsers understood. The double-colon::beforeis the modern standard that distinguishes pseudo-elements from pseudo-classes — prefer it.
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 anurl()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-incrementto 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
contentis 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.
::beforeis the first child inside the element — not before the element's opening tag.
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.
Related references
::after— insert content after an element.content— the property that defines what::beforeinserts.counter-increment— build automatic numbering with generated content.position— place a generated element precisely.