Question
How can you use the CSS content property to insert characters that are normally written as HTML entities?
For example, why does this CSS display the literal text instead of inserting a non-breaking space?
.breadcrumbs a::before {
content: ' ';
}
What is the correct way to insert a non-breaking space or similar special character with CSS content?
Short Answer
By the end of this page, you will understand that CSS content does not parse HTML entities like . Instead, CSS inserts plain text strings or Unicode characters. You will learn how to add special characters correctly using direct characters or Unicode escape sequences such as "\00a0".
Concept
CSS and HTML are parsed differently.
HTML entities like , &, and © are part of HTML syntax, not CSS syntax. That means the CSS content property does not interpret as a non-breaking space. It sees it as an ordinary string of characters and prints it exactly as written.
For example:
content: ' ';
This means:
- start a string
- place the characters
&,n,b,s,p,; - end the string
So the browser displays literally.
To insert special characters with CSS content, use one of these approaches:
- type the actual character directly, if appropriate
- use a Unicode escape sequence such as
"\00a0"for a non-breaking space
This matters because pseudo-elements like ::before and ::after are commonly used for:
- separators in breadcrumbs
- decorative icons
- quotation marks
- arrows and bullets
- labels like
RequiredorNew
If you do not understand how content handles characters, your UI may show the wrong text or spacing.
Mental Model
Think of HTML entities as a language that HTML understands, but CSS does not.
- HTML sees
and translates it into a special space. - CSS sees
inside quotes and treats it like a normal word.
A simple analogy:
- HTML entities are like commands written for one machine.
- CSS
contentis a different machine with different commands. - If you send an HTML command to CSS, CSS does not translate it. It just prints it.
So when using content, think in terms of:
- plain text strings
- Unicode characters
- Unicode escape codes
not HTML entities.
Syntax and Examples
The basic syntax for content with pseudo-elements looks like this:
selector::before {
content: "text";
}
selector::after {
content: "text";
}
Example 1: Insert a normal string
.note::before {
content: "Note: ";
}
This adds the text Note: before the element.
Example 2: Insert a non-breaking space
.breadcrumbs a::before {
content: "\00a0";
}
\00a0 is the Unicode code point for a non-breaking space.
Example 3: Insert a separator with spacing
.breadcrumbs a + a::before {
content: " / ";
}
This adds / before every breadcrumb link except the first one.
Example 4: Insert a copyright symbol
.footer::before {
content: "\00a9 ";
}
This displays the copyright symbol followed by a normal space.
Example 5: Direct character instead of escape
You can sometimes type the character directly:
.footer::before {
content: "© ";
}
This is valid too, as long as your file encoding is handled correctly.
Important note
Pseudo-elements usually need ::before or ::after to display generated content:
.label::after {
content: " *";
color: red;
}
Step by Step Execution
Consider this CSS:
.breadcrumbs a + a::before {
content: "\00a0>\00a0";
}
And this HTML:
<nav class="breadcrumbs">
<a href="/">Home</a>
<a href="/products">Products</a>
<a href="/products/shoes">Shoes</a>
</nav>
What happens step by step
- The browser finds every
ainside.breadcrumbs. - The selector
a + amatches every link that comes immediately after another link. - That means:
Homeis not matchedProductsis matchedShoesis matched
- For each matched element,
::beforecreates a pseudo-element before the link text. - The
contentvalue"\00a0>\00a0"is interpreted as:- a non-breaking space
- the
>character - another non-breaking space
- The rendered output becomes visually similar to:
Home > Products > Shoes
Why non-breaking spaces help
A normal space can wrap at the end of a line. A non-breaking space helps keep the separator attached more tightly to nearby text, depending on the layout.
Real World Use Cases
Developers use CSS content for many small interface details.
Breadcrumb separators
.breadcrumbs a + a::before {
content: " / ";
}
Useful for navigation trails.
Required form labels
.required label::after {
content: " *";
color: red;
}
Adds a visual required marker.
External link indicator
a.external::after {
content: " ↗";
}
Shows that a link opens an external resource.
Quotes or decorative marks
blockquote::before {
content: "\201C";
}
Adds an opening quotation mark.
Status badges
.new::before {
content: "New: ";
font-weight: bold;
}
Adds short labels without changing the HTML.
These uses are best for presentation, not critical content that users must always access.
Real Codebase Usage
In real projects, developers usually use CSS content for small presentational additions rather than meaningful data.
Common patterns
Visual separators
.breadcrumbs li + li::before {
content: " / ";
color: #666;
}
This avoids adding separator markup into every breadcrumb item.
Icons with Unicode characters
.download-link::before {
content: "\2193 ";
}
Good for lightweight decorative icons.
Guarding the first item
Instead of adding a separator before every item, developers often use selectors like:
.item + .item::before {
content: ", ";
}
This is similar to a guard clause in programming: only apply the separator when there is a previous item.
Keeping content decorative
Teams usually avoid placing essential business information only in ::before or ::after, because generated content may not be as reliable for accessibility, translation, or copy/paste workflows.
Prefer HTML for meaningful text
If the content is important, such as error messages, prices, or labels needed by screen readers, developers typically put it in the HTML or generate it from templates or JavaScript instead.
Common Mistakes
1. Using HTML entities in CSS strings
Broken example:
.box::before {
content: "©";
}
This prints © literally.
Correct:
.box::before {
content: "\00a9";
}
or
.box::before {
content: "©";
}
2. Forgetting to use a pseudo-element
Broken example:
.box {
content: "Hello";
}
For normal elements, content does not work the way beginners often expect.
Correct:
.box::before {
content: "Hello";
}
3. Using one colon in modern code without consistency
Older CSS used :before. Modern CSS prefers ::before and ::after.
.box::before {
content: "*";
}
Most browsers support both, but ::before is clearer.
4. Forgetting quotes around strings
Broken example:
.box::before {
content: Hello;
}
Correct:
.box::before {
content: "Hello";
}
5. Assuming generated content is always accessible
Using CSS to add important warnings or instructions can be risky.
Avoid this for critical information:
.error::before {
content: "Form submission failed: ";
}
Prefer real HTML content for important messages.
6. Using the wrong Unicode escape format
CSS Unicode escapes start with a backslash.
Correct:
content: "\00a0";
Not:
content: "00a0";
Comparisons
| Approach | Works in CSS content? | Example | Notes |
|---|---|---|---|
| HTML entity | No | " " | Printed literally in CSS |
| Direct character | Yes | "©" | Easy to read if encoding is reliable |
| Unicode escape | Yes | "\00a9" | Best when you want explicit, portable character insertion |
| Regular text string | Yes | "Hello" | Most common use |
::before vs ::after
| Pseudo-element | Purpose | Example |
|---|---|---|
::before | Insert content before the element's content | Add icons before links |
::after | Insert content after the element's content | Add badges or arrows after text |
CSS content vs real HTML text
| Option | Best for | Avoid for |
|---|---|---|
CSS content | Decorative labels, separators, symbols | Critical text or structured content |
| HTML text | Meaningful content, accessible labels, data | Purely decorative repetition |
Cheat Sheet
Quick rules
- CSS
contentdoes not understand HTML entities like - Use
::beforeor::after - Use quoted strings for text
- Use Unicode escapes for special characters
- Prefer HTML for important content
Common syntax
.element::before {
content: "Hello";
}
.element::before {
content: "\00a0";
}
Useful Unicode values
- Non-breaking space:
\00a0 - Copyright:
\00a9 - Right arrow:
\2192 - Opening double quote:
\201C - Closing double quote:
\201D - Bullet:
\2022
Example fixes
Wrong:
content: " ";
Right:
content: "\00a0";
or
content: " ";
Good breadcrumb pattern
.breadcrumbs a + a::before {
content: " / ";
}
FAQ
Why does print literally in CSS?
Because is an HTML entity, and CSS does not parse HTML entities inside content strings.
How do I insert a non-breaking space in CSS?
Use a Unicode escape:
content: "\00a0";
Can I type the actual special character directly in CSS?
Yes. For many characters, you can write them directly, such as © or a real non-breaking space, but Unicode escapes are often clearer.
Should I use :before or ::before?
Use ::before in modern CSS. :before is older syntax but still widely supported.
Is CSS-generated content good for accessibility?
It can be acceptable for decorative content, but important information should usually be in the HTML.
Can I add icons using CSS content?
Yes. You can use Unicode symbols or icon fonts, but simple Unicode characters are often the easiest option.
Does content work on normal elements without pseudo-elements?
Usually, beginners should think of content as something used with ::before and ::after. That is the common and practical use case.
Mini Project
Description
Build a breadcrumb navigation style that inserts separators between links using CSS generated content. This demonstrates the correct way to add visual characters in CSS without using HTML entities like .
Goal
Create breadcrumb links that display a separator before each item except the first, using ::before and valid CSS content values.
Requirements
- Create a breadcrumb navigation with at least three links.
- Add separators using CSS
::beforeinstead of putting separator text in the HTML. - Do not show a separator before the first breadcrumb item.
- Use either plain text separators or Unicode escapes in the
contentproperty. - Keep the HTML clean and readable.
Keep learning
Related questions
Angular ngClass Conditional Class Binding Explained
Learn how to use Angular ngClass for conditional classes, fix common binding mistakes, and understand why this template error happens.
CSS :not() Selector for Elements Without a Class or Attribute
Learn how to use the CSS :not() selector to target elements that do not have a specific class or attribute, with examples and common pitfalls.
CSS Font Scaling Relative to Container Size: %, em, rem, vw, and Responsive Text
Learn how CSS font scaling really works and how to make text responsive using %, em, rem, vw, clamp(), and media queries.