Generated Content in CSS: A Complete Guide

Master the content property with ::before and ::after pseudo-elements. Learn accessibility best practices and practical patterns for modern web development.

CSS generated content is one of the most powerful yet underutilized features in modern web development. While many developers know about adding pseudo-elements for decorative purposes, few understand the full capabilities of the content property and its role in building accessible, maintainable interfaces.

In modern web development with frameworks like Next.js, understanding how CSS generated content works helps developers make informed decisions about where to use CSS-only solutions versus HTML/JavaScript alternatives. Our team at Digital Thrive regularly applies these techniques in custom web development projects to create efficient, performant interfaces.

This comprehensive guide covers everything from basic text insertion to advanced accessibility patterns that ensure your designs work for everyone. Whether you're building responsive websites or complex web applications, mastering CSS generated content is an essential skill for modern frontend development.

What You'll Learn

Content Property Fundamentals

Master the syntax and value types of the CSS content property

Pseudo-Elements Deep Dive

Understand ::before and ::after positioning and display behavior

Accessibility Integration

Make generated content accessible to screen readers with proven patterns

Practical Examples

Real-world patterns for icons, badges, tooltips, and layouts

Best Practices

Guidelines for maintainable, performant CSS-generated content

Common Patterns

Clearfix, custom bullets, status indicators, and more

The content Property

The content property is the foundation of CSS generated content. According to the W3C CSS Generated Content Module Level 3 specification, this property accepts a variety of values that determine what content to generate:

.element::before {
 content: "→"; /* String value */
 content: url("icon.svg"); /* Image value */
 content: counter(name); /* Counter value */
 content: attr(data-label); /* Attribute value */
}

String Values

The simplest form of content is a string value, specified within quotes:

.required::after {
 content: " *";
 color: #dc2626;
}

String values support unicode escapes for special characters and can include spaces, symbols, and text formatting. This pattern is commonly used for required field indicators in form development.

Image Values

The content property can insert images using the url() function:

.icon-external::after {
 content: url("/icons/external-link.svg");
 display: inline-block;
 width: 12px;
 height: 12px;
 margin-left: 4px;
}

Modern CSS also supports gradient() for simple visual effects without additional image requests. This approach reduces HTTP requests and improves page load times, especially important for performance optimization.

Attribute Values with attr()

The attr() function reads the value of an HTML attribute and uses it as content:

[data-count]::after {
 content: " (" attr(data-count) ")";
}

This powerful pattern enables dynamic content based on data attributes, reducing the need for JavaScript in many scenarios. It's particularly useful in Vue.js and React applications where you want to minimize client-side logic.

Counter Values

CSS counters enable automatic numbering for nested structures:

.section h2::before {
 counter-increment: section;
 content: counter(section) ". ";
}

For nested lists, use counters() with a separator:

.nested-list li::before {
 counter-increment: item;
 content: counters(item, ".") " ";
}

The ::before and ::after Pseudo-Elements

The ::before and ::after pseudo-elements create virtual elements as the first and last child of the selected element, respectively. As documented in MDN Web Docs, these pseudo-elements exist in the document but are not part of the actual DOM, making them efficient for presentational purposes.

Positioning and Display

By default, pseudo-elements are inline boxes. To use them as block-level layout elements, change their display property:

.card::before {
 content: "";
 display: block;
 width: 100%;
 height: 4px;
 background: linear-gradient(90deg, #3b82f6, #8b5cf6);
 border-radius: 4px 4px 0 0;
}

Practical Patterns

Clearfix Pattern - Essential for float-based layouts:

.clearfix::after {
 content: "";
 display: table;
 clear: both;
}

Notification Badge - Using attr() for dynamic content:

.notification::after {
 content: attr(data-count);
 position: absolute;
 top: -8px;
 right: -8px;
 background: #dc2626;
 color: white;
 padding: 2px 6px;
 border-radius: 9999px;
}

Custom List Bullets:

.custom-list li::before {
 content: "✓";
 margin-right: 8px;
 color: #10b981;
}

These patterns are fundamental techniques used throughout modern frontend development and are particularly valuable when building progressive web applications that prioritize performance.

Accessibility Considerations

The Screen Reader Problem

CSS-generated content creates visual content only, which is ignored by assistive technologies. This has significant implications for how we use generated content in accessible web applications.

Making Generated Content Accessible

Visually Hidden Content in HTML:

<span class="required">
 <span class="sr-only">This field is required</span>
</span>
.sr-only {
 position: absolute;
 width: 1px;
 height: 1px;
 padding: 0;
 margin: -1px;
 overflow: hidden;
 clip: rect(0, 0, 0, 0);
 white-space: nowrap;
}

Using ARIA Attributes:

<button aria-label="Close dialog" class="close-button">
 <span aria-hidden="true">×</span>
</button>

Guidelines for Accessible Use

  1. Use generated content for decoration only - If the content conveys information to visual users, it must also be available to screen reader users through HTML or ARIA.
  2. Use sr-only text for labels - When generated content needs a label, add visually hidden text in the HTML.
  3. Consider aria-hidden for decorative pseudo-elements - Add aria-hidden to the parent element to prevent confusion.
  4. Test with real screen readers - Always verify accessibility with actual assistive technology.

Following these guidelines ensures your website meets WCAG accessibility standards while benefiting from CSS-generated content for visual enhancements.

Common Use Cases

Social Media Links with Icons

.social-link.github::before {
 content: "";
 display: inline-block;
 width: 20px;
 height: 20px;
 background-image: url("/icons/github.svg");
 background-size: contain;
 margin-right: 8px;
 vertical-align: middle;
}

Custom Tooltips

[data-tooltip] {
 position: relative;
}

[data-tooltip]::after {
 content: attr(data-tooltip);
 position: absolute;
 bottom: 100%;
 left: 50%;
 transform: translateX(-50%);
 padding: 8px 12px;
 background: #1f2937;
 color: white;
 font-size: 12px;
 border-radius: 4px;
 white-space: nowrap;
 opacity: 0;
 pointer-events: none;
 transition: opacity 0.2s;
}

[data-tooltip]:hover::after {
 opacity: 1;
}

Status Indicators

.status::before {
 content: "";
 display: block;
 width: 8px;
 height: 8px;
 border-radius: 50%;
 margin-right: 6px;
}

.status.active::before { background: #10b981; }
.status.pending::before { background: #f59e0b; }
.status.inactive::before { background: #6b7280; }

These patterns are commonly implemented in custom web applications to enhance user experience without JavaScript overhead. They are especially valuable for ecommerce website development where visual status indicators improve the shopping experience.

Best Practices for Modern Web Development

When to Use Generated Content

Use generated content for:

  • Decorative elements like icons, arrows, and visual flourishes
  • CSS-only layouts like clearfix patterns
  • Presentational markers like required field indicators
  • Custom list bullets and quotation marks

Avoid generated content for:

  • Critical content that must be accessible
  • Content that needs to be interactive
  • Content that search engines should index
  • Dynamic content that changes frequently

Performance Considerations

Generated content has minimal performance impact because:

  • Pseudo-elements don't add nodes to the DOM
  • Browser rendering engines optimize pseudo-element rendering
  • Changes to generated content trigger style recalculation, not layout changes

This makes CSS generated content an excellent choice for high-performance website development where every kilobyte and render cycle matters.

Tailwind CSS Approach

In Tailwind CSS, pseudo-elements require custom utilities or arbitrary values:

<span class="before:content-['→'] before:ml-2">
 Continue
</span>

Maintenance and Organization

For maintainable code:

  • Keep generated content styles co-located with the element they style
  • Use descriptive class names for pseudo-element styles
  • Document when generated content conveys visual-only meaning
  • Include accessibility considerations in code comments

These practices align with our frontend development standards for building maintainable websites that scale.

Frequently Asked Questions

Build Accessible, Maintainable Websites

Our team specializes in modern web development practices that prioritize performance, accessibility, and maintainability. Contact us to discuss your project.

Sources

  1. MDN Web Docs - CSS generated content - Comprehensive official documentation covering the CSS Generated Content Module Level 3, pseudo-elements, and practical examples
  2. Sara Soueidan - Alternative text for CSS-generated content - In-depth accessibility guide on making generated content accessible to screen readers
  3. W3C CSS Generated Content Module Level 3 - Official W3C specification for CSS generated content
  4. W3Schools - CSS content Property - Basic reference with examples for content property usage