You will be able to generate small pieces of text or decorative boxes inside an element using CSS pseudo-elements ::before and ::after, and know when this is appropriate instead of adding real HTML.
What it is
Pseudo-elements are virtual boxes that CSS can insert inside a selected element. The most common are ::before and ::after. They do not exist in the HTML source, but they are attached to a real element and can inherit some styles from it. The content property is what makes them appear. Without content, the pseudo-element is not generated.
Related terms include content, attr(), counter(), quotes, and ::marker. A pseudo-element can contain a string, an image, an attribute value, or a generated counter. It is useful for small additions that are visual rather than structural.
Why it matters
- It keeps simple labels, bullets, badges, and decorative marks out of the HTML.
- It lets you add visual cues such as required-field asterisks, download icons, or quote marks.
- It can generate repeated text from data attributes, reducing markup duplication.
- It helps create small decorative shapes or overlays without extra wrapper elements.
- It supports counters for numbered lists, figure captions, or section numbering.
Syntax or steps
- Select the element and add
::beforeor::after. - Set
contentto a quoted string,url(),attr(), or a counter. - Use
content: ""when you only need a styled box, such as a dot or line. - Style the generated box with properties such as
background,padding,color, orposition. - Use
displayor positioning if the generated content needs to behave like a block or overlay.
Example
<span class="badge">Sale</span>
.badge {
display: inline-block;
padding: 4px 8px;
background: #eee;
}
.badge::after {
content: "NEW";
background: gold;
color: #222;
padding: 2px 6px;
margin-left: 6px;
border-radius: 4px;
}
Part by part
- The HTML contains only the real element:
<span class="badge">Sale</span>. .badgestyles the visible badge..badge::aftercreates a generated box after the text “Sale”.content: "NEW"inserts the visible string.background,padding,margin-left, andborder-radiusstyle the generated box.
Common mistakes
- Forgetting
content. Ifcontentis missing, the pseudo-element will not render. Usecontent: ""for an empty decorative box. - Using it for essential information. Generated content may not be announced consistently by assistive technology. Put important text in real HTML.
- Assuming it is a real element. You cannot select
::beforeor::afteras DOM nodes with JavaScript. - Ignoring layout. Generated content is inline by default, so long strings or overlays may need
display: block,position: absolute, or spacing adjustments.
When to use it
Use pseudo-element content for small, presentational additions. Use real HTML when the text is meaningful, searchable, editable, or needed by assistive technology.
| Approach | Best for | Avoid when |
|---|---|---|
::before / ::after | Decorative labels, icons, counters, simple badges | Important content, SEO text, user-editable text |
| Real HTML element | Meaningful text, links, buttons, form labels | Only visual decoration that should not affect content |
::marker | Styling list markers | Complex generated content inside arbitrary elements |
Practice
Guided exercise: Add a red asterisk before every required label.
<label class="required">Email</label>
.required::before {
content: "* ";
color: red;
}
Expected output: * Email with the asterisk in red.
Challenge: Use attr() to show a tooltip label from a data attribute.
<span class="tip" data-tip="Download PDF">File</span>
.tip::after {
content: attr(data-tip);
margin-left: 8px;
color: #555;
}
Solution hint: attr(data-tip) reads the value of data-tip from the HTML element.
Quick check
Which property must be present for ::before or ::after to generate content?
content. Without it, the pseudo-element is not created.
Summary
Pseudo-element content lets CSS insert small generated boxes using ::before and ::after. It is useful for decoration and repeated visual cues, but meaningful information should stay in real HTML.