Reputation: 480
I want to replace some third party generated content using pure CSS. There are various techniques covered by other questions but the basic idea is hide the exiting content and add new content with pseudo selectors.
I'm interested in whether this is an acceptable thing to do from an accessibility point of view. Would a screen reader see both bits of text or only the original? Should the CSS be wrapped in @media screen {} to avoid both being used?
In my situation I can only use CSS. I can't edit the HTML or use any JavaScript. Is there any way to present only the replacement text to a screen reader?
.third-party-content {
font-size:0;
}
.third-party-content:before {
content:"lovely replacement";
font-size:initial;
}
<div class="third-party-content">unwanted garbage</div>
Upvotes: 1
Views: 671
Reputation: 14752
Don't use CSS generated text to convey meaningful information at all.
Screen readers don't behave the same. Some of them always read it, some of them never, and some of them sometimes do or don't depending on other properties. For example, NVDA reads CSS generated text most of the time; Jaws rarely does (if ever it does sometimes).
Anyway, according to the base separation principle: content/structure=HTML, behavior/action=JavaScript, appearance=CSS, it isn't semantically correct to let CSS generate meaningful text.
It should be done in HTML. In fact the CSS Content
propertiy should never be used for something else than text icons and other pure visual things that don't really matter for general understanding if they are skipped / not shown / not read.
Upvotes: 4
Reputation: 17485
Changing the font-size
to 0 just changes the visual appearance of the text but does not hide it from a screen reader. A screen reader does not care what size the font is. It's just text that will be read.
When a screen reader reads text, it's called the "accessible name". The accessible name is computed according to these rules - https://www.w3.org/TR/accname-1.1/#step2. In particular, see step 2.F.ii
"ii. Check for CSS generated textual content associated with the current node and include it in the accumulated text. The CSS
:before
and:after
pseudo elements can provide textual content for elements that have a content model."
One way to hide text from a screen reader is to use the aria-hidden
attribute but that would require changing the HTML, which you stated you can't do. Text is also hidden using standard display:none
, but that would obviously hide your :before
text too.
Using CSS tricks to visually hide text, such as clip
, position
, width
, etc, again just visually hides the text but does not hide it from a screen reader.
I'm not a CSS expert but building on your attempted solution of font-size
, I added visibility:hidden
and it seemed to work. I know hidden
just makes the text invisible but still takes up space on the screen, but when combined with your font-size:0
(and inherit
) it prevents the "unwanted garbage" from taking up any space so if you had an element adjacent to your original, you wouldn't have a big gap between the two.
visibility:hidden
does hide the element from the screen reader.
.third-party-content {
font-size:0;
visibility:hidden;
}
.third-party-content:before {
content:"lovely replacement";
font-size:initial;
visibility:initial;
}
You cannot use display:none
in a similar solution because as soon as the parent is hidden, the :before
is hidden too.
Update: This solution works with NVDA (screen reader) on firefox and VoiceOver on iOS. (Chrome with screen readers is typically not tested because Chrome has sporadic support for screen readers.) It does not work with JAWS on Internet Explorer but IE seems to have two problems. The first is that your font-size:initial
does not work on the :before
. I had to set it to font-size:16px
. Second is that IE does not correctly compute the text to be read as noted in step 2.F.ii above. IE is not honoring the content
property so "unwanted garbage" is still read (and "lovely replacement" is not read). Since step 2.F.ii is a W3 spec, I'd say IE has a bug.
If content
were correctly read by IE, then there might still be a problem. Since font-size:inherit
doesn't work in IE, visibility:inherit
might not work either. (I tried a simple case and it didn't work. Setting visibility:visible
on :before
also didn't work on IE.)
Upvotes: 2