content has no effect on a regular, ordinary element — it's specifically read by the ::before and ::after pseudo-elements, which don't render at all unless content is explicitly set, even to an empty string, content: "", the classic technique used purely to trigger a pseudo-element's existence for styling purposes, like a decorative shape, without needing any actual generated text. content can also insert a literal string, reference an attribute's value with attr(name), or insert certain special characters and icons, and generated content inserted this way is not selectable as real text and isn't included in the page's actual DOM or accessible to screen readers the same way genuine content is, making it unsuitable for anything meaningfully informational.
1Understanding Content
content has no effect on a regular, ordinary element — it's specifically read by the ::before and ::after pseudo-elements, which don't render at all unless content is explicitly set, even to an empty string, content: "", the classic technique used purely to trigger a pseudo-element's existence for styling purposes, like a decorative shape, without needing any actual generated text. content can also insert a literal string, reference an attribute's value with attr(name), or insert certain special characters and icons, and generated content inserted this way is not selectable as real text and isn't included in the page's actual DOM or accessible to screen readers the same way genuine content is, making it unsuitable for anything meaningfully informational.
A ::before or ::after pseudo-element renders nothing at all unless content is explicitly set, even to an empty string — this is the single most common reason a pseudo-element you've styled doesn't appear to be working.
.required::after {
content: " *";
color: red;
}2Practical Example
Here is a real-world application of Content showing how it is used in production CSS code.
.icon-box::before {
content: "";
display: block;
width: 10px;
height: 10px;
background: blue;
}3Best Practices
Follow these guidelines when working with Content:
1. Always set content, even to an empty string content: "", on a ::before/::after pseudo-element you intend to actually render, since it won't appear without it
2. Use attr(data-something) within content to dynamically insert an HTML attribute's value into generated content
3. Avoid putting meaningfully informational content in a ::before/::after's content value, since it's not selectable text and isn't reliably accessible to screen readers — use it for purely decorative or presentational purposes instead
Tip: A ::before or ::after pseudo-element renders nothing at all unless content is explicitly set, even to an empty string — this is the single most common reason a pseudo-element you've styled doesn't appear to be working.
.required::after {
content: " *";
color: red;
}