The CSS Generated Content Trap: When Visual Design Breaks Screen Readers

Here's something that catches even experienced developers off guard: you can build a form that looks perfectly accessible, passes basic validation, and still completely fails disabled users. I'm looking at a page that demonstrates exactly this problem — and it's more common than you might think.
The WCAG repository example (opens in new window) shows four classic CSS-generated content failures that I see constantly in production code. Each one looks fine visually, but creates an invisible wall for screen reader users.
The Asterisk Problem That Isn't Really About Asterisks
Let's start with the most ubiquitous example: required field indicators. The page shows an email field with a red asterisk generated via CSS ::before pseudo-element. Visually, it's clear which fields are required. But when a screen reader user tabs through the form, they hear "Email, edit text" — no indication whatsoever that the field is required.
This isn't just a minor usability hiccup. For someone using a screen reader, discovering required fields through trial and error means:
- Filling out an entire form
- Hitting submit
- Getting an error message
- Backing up to find what they missed
- Repeating this process for each required field
What should take 30 seconds becomes a 5-minute frustration cycle. And that's assuming they don't just abandon the form entirely.
The technical issue is straightforward: CSS-generated content using ::before and ::after pseudo-elements isn't exposed to the accessibility tree. Screen readers literally cannot see it. According to WCAG 1.1.1 (Non-text Content) (opens in new window), any meaningful visual information needs a text alternative.
When Success Looks Like Failure
The status indicator example is particularly insidious. The page shows "Download complete" with a green checkmark generated via CSS. A screen reader announces "Download complete" — which sounds like it's working perfectly. But the user doesn't get the crucial context that this represents success.
Imagine you're uploading a critical document and you hear "File processed." Is that good? Bad? Still working? The visual checkmark provides essential context that's completely lost to screen reader users. They're left guessing whether their action succeeded or failed.
This connects to broader patterns I've been tracking in accessibility implementation failures. Teams often focus on making text readable by screen readers while missing the semantic meaning conveyed through visual design.
The Button That Isn't Really There
The navigation examples show hamburger menu (☰) and close (✕) buttons generated entirely through CSS. Screen readers announce these as "button" with no indication of their purpose. Users know something is clickable, but have no idea what it does.
This is where the operational capacity challenge becomes clear. Most development teams I work with have someone who knows to add aria-label attributes to buttons. But when the meaningful content is generated through CSS, that knowledge doesn't automatically transfer. The button exists in the HTML, but its purpose lives in the stylesheet.
The Rating System Nobody Can Rate
The star rating display might be the most problematic example. Five stars (★★★★☆) generated via CSS ::after show a clear 4-out-of-5 rating visually. But screen readers get nothing — not even a hint that rating information exists.
For an e-commerce site, this means screen reader users can't evaluate products based on customer ratings. They're making purchasing decisions with significantly less information than sighted users. That's not just a usability problem; it's a fundamental equity issue.
Why This Keeps Happening
These failures persist because they represent a disconnect between visual design and semantic markup. CSS is incredibly powerful for creating visual effects, and ::before and ::after pseudo-elements are elegant solutions for decorative content. The problem comes when that "decorative" content carries meaning.
I see this pattern constantly in modern web development:
- Designer creates a visual treatment using icons or symbols
- Developer implements it using CSS pseudo-elements (clean, maintainable code)
- Visual testing confirms it looks correct
- Accessibility testing (if it happens) focuses on color contrast and keyboard navigation
- The semantic meaning gap goes unnoticed
Automated testing tools often miss these issues because they're checking for the presence of alternative text, not evaluating whether CSS-generated content needs it. As I discussed in The False Promise of Automated Accessibility Testing, these tools excel at catching missing alt attributes but struggle with semantic context.
Fixing the Fundamental Pattern
The solutions aren't technically complex, but they require thinking differently about the relationship between visual design and semantic meaning.
For required field indicators, the simplest approach is adding actual text content:
<label>Email <span aria-label="required">*</span></label>
For status indicators, provide semantic context:
<div class="status-message" aria-label="Download completed successfully">
Download complete
</div>
For navigation buttons, describe the action:
<button class="menu-toggle" aria-label="Open navigation menu"></button>
For rating displays, include the actual rating data:
<div class="star-rating" aria-label="4 out of 5 stars">
<!-- CSS can still generate the visual stars -->
</div>
Building Better Defaults
The real solution isn't just fixing individual instances — it's building development practices that prevent these gaps. When I work with teams on improving their organizational capacity, we focus on making accessibility considerations part of the design-to-development handoff.
That means:
- Design systems that specify both visual treatment and semantic requirements
- Code review processes that flag CSS-generated meaningful content
- Testing protocols that include screen reader verification
- Component libraries with accessibility built in from the start
The CSS-generated content trap is particularly frustrating because it represents good intentions implemented poorly. Developers are trying to write clean, maintainable code. Designers are creating clear visual hierarchies. But without considering the accessibility tree alongside the visual design, even well-intentioned teams create barriers.
Every CSS pseudo-element that conveys meaning should trigger a question: "How will a screen reader user understand this?" Getting teams to ask that question consistently — and know how to answer it — is where the real progress happens.
The examples in this WCAG repository page aren't edge cases. They're representative of patterns I encounter on major websites every week. Which means fixing them isn't just about compliance — it's about ensuring that the web actually works for everyone who uses it.
About Marcus
Seattle-area accessibility consultant specializing in digital accessibility and web development. Former software engineer turned advocate for inclusive tech.
Specialization: Digital accessibility, WCAG, web development
View all articles by Marcus →Transparency Disclosure
This article was created using AI-assisted analysis with human editorial oversight. We believe in radical transparency about our use of artificial intelligence.