Developers often ask how various CSS declarations translate to the screen reader experience. Properties that are strictly visual – such as color, border, font, margin, padding – are transparent, but what about those that inject content, like ::before
and ::after
? What about properties that communicate meaning, like list-style
and line-through
? And then there are those that visually position or crop content, like clip
, position
, display
, overflow
, height
, width
, visibility
… the list goes on. We all know that using CSS to generate content is bad, just as we all know that we should never ever exceed the speed limit. It happens.
Earlier this year, three colleagues and I tested and documented the behavior of some widely-used CSS declarations in screen readers, leaving the screen reader user settings at their defaults. We reported our findings at AccessU 2017 and will present again, with some new material added, at Accessing Higher Ground.
In addition to myself, our team included CB Averitt and Steve Sawczyn of Deque, and Birkir Gunnarsson. We tested the following screen reader-browser pairings:
- JAWS/IE 11
- JAWS/Chrome
- JAWS/Firefox
- NVDA/Firefox
- NVDA/Chrome
- VoiceOver/Safari
- VoiceOver/Mobile Safari
- Talkback/Mobile Chrome
Key Takeaways
Different screen reader/browser pairings behave differently.
It’s tempting to assert that if you do x, “the screen reader” will announce y. Sometimes it really is just that simple, but in a surprising number of situations, it just isn’t that absolute. For example:
- Across the pairings we tested,
counter
was announced three different ways. (CSS counters are “variables” maintained by CSS whose values can be incremented by CSS rules, to track how many times they are used.) - Using
vertical-align:super
to communicate cents within a dollar amount worked in half of our pairings. In the other half, $1299 was announced as $1,299. - Applying a transition to
opacity:0; visibility:hidden
on a paragraph, we logged five slightly different behaviors across the eight pairings.
DOM order is everything.
One of the consistencies we found is that, regardless of CSS position, content is read in the order that it appears in the DOM. For example, appending a <div>
to the end of the <body>
and then using position:absolute
to boost it to the top of the viewport will not change the reading order in the screen reader – it will still come last (and in this case, we can safely say “the” screen reader).
The same is true for floats. Applying float:right
to an element typically positions it “after” (to the right of) the element that follows it in the DOM, making the visual reading order the opposite of the DOM order. Since the DOM order is what determines the screen reader reading order (and the tab order, in the case of active elements), the elements will be announced in the opposite order from the visual reading order.
Containers are only visual.
Many CSS properties are available to apply dimensions to containers – height
, width
, max-height
, max-width
, clip
– and overflow
and text-overflow
determine whether and how content exceeding the bounds of the container are rendered. Across all of our test pairings, all of these are transparent to screen readers. Regardless of the content being clipped out visually, or obscured by overflow:hidden
, the screen reader will announce all content in the container. Even opacity:0
has no effect in the screen reader environment; the content is announced nonetheless.
The moral of the story
All of this really highlighted the value of accessibility-minded development and pre-launch testing – in a wide variety of browser-screen reader combinations – to ensure that all website visitors enjoy a consistent, equivalent experience.
For more information
This is just a brief overview of our findings. For details, please check us out at Accessing Higher Ground in Westminster, Colorado on Friday, November 17, 2017 or contact john@webaim.org.
Great original research, kudos to authors.
But still leaves the practical question unanswered: how much testing is too much, and how little testing is too little?
Beyond practical considerations, how much of this screen reader behavior variability is attributable to platform differences and how much to screen readers themselves?
Even though I find accessibility very important, I have issues with the general attitude of “devs should make sure behaviour is consistent for screen-readers”.
Don’t get me wrong, I totally believe devs should make their content accessible, but if screen readers X, Y, and Z all produce different results, then the issue is with the screen readers.
very much like browser rendering inconsistencies. There’s a spec to be followed and if a browser deviates from the spec, then it shouldn’t be up to the dev to “fix” that.
I know it’s not this black and white usually (we all have dealt with our ie.css files back in the day for example), but I think those who author screen readers should step up and make sure all readers adhere to the same spec.
Great work! One odd thing I’ve found is in using flexbox. While flexbox allows you to reorder the children, it should still be read in DOM order. Last time I checked, in FFOX, it was not (and for that reason, we don’t use the order property). Did you all do any flexbox testing? I’d be interested in the results.
Cheers!
Looking forward to hearing more at Accessing Higher Ground! See you there.
I find it much better, long term, to ensure as much as possible, no – everything – is correct in source HTML.
For example, prefer removing/inserting content over hiding/showing. I can see that hidden content, and sometimes, without hacking, some sites just glitch and suddenly it’s there.
I’ve also seen many cases where authors have visually hidden content intended only for screen reader users when it would actually be of benefit to sighted users, too, even automatically-hidden content like image alt text.
Also, if you’re into industry-strength workmanship, CSS-only solutions tend to be inappropriate for language or locale sensitive cases (injecting words into a page, or formatting cents/pence superscript).
I’m sure somebody could indeed design a CSS localisation solution for such cases, but having everything correct in source HTML to start with is more robust and usually simpler.
This is a surprise! I knew that screen readers read codes in a linear way and CSS don’t get in the way. Thank you very much for this very useful info.
But what about ::before and ::after generated content? That’s particularly what I’d like to know. I manage a website with many different users who are very very bad at remembering to do things like indicating PDF links. I’d like to add a filetype indicator as generated content in the CSS, but have understood that it will be skipped by screenreaders, is that correct?
I always turn CSS off, and assume that’s what a screen reader is going to “see” and read out.
That might not be a 100% accurate assumption, but HTML is for content and CSS is for design (seperation of concerns). A screen reader should be interested in the former and not so much the latter.
This is very helpful, thank you!
The only thing that surprises me is that it seems generated content was outright bad. If I get Jens Meiert right, for example, then there are cases when generated content is useful. The cases Karl Groves mentions, as with marking PDF links, look acceptable for Meiert. Again if I understand them well, maybe they can comment.
I am currently involved in a pretty large scale accessibility overhaul for a number of government sites. The inconsistencies between various screen readers / browsers / OSs is almost laughable. It seems absurd to me that a law could be passed that requires compliance with undefined and inconsistent specifications.
So far, it seems following wcag/w3c documentation is only a start and is only actually helpful in the most simple situations. Tables have been a nightmare (if anyone can come up with a decent solution for a responsive, mobile-friendly table that works with screenreaders that isn’t more aria- attributes than actual table markup I’m all ears). Description lists just come out as a block of text. Pseudo elements are read by screenreaders (and as far as I can tell, there’s no way to hide them from screenreaders). Changing the display: property of an element can cause screenreaders to present them differently. Flexbox order vs DOM order – seems to depend…
And getting one screen reader to behave correctly doesn’t mean others will. Voiceover is inconsistent between desktop and mobile. Each screenreader can be configured differently as well, so whats the standard there.
I think everyone should be able to access whatever content they want in a way that’s appropriate for them, but this feels a little like we’re being legally required to support a very broad category of software with seemingly few predictable standards.
This is not just frustrating for developers, it also is hard for users. I would like it if I could just use one browser/screen reader combination for computers and one for mobile. But sadly, I’m stuck having at least 2 screen readers on the computer and 2 browsers. The phones only have one screen reader handy, so that’s all I have on Android and iOS when I was using it. Having to bounce browser /screen reader combinations just because one doesn’t read the page accurately is not helpful. I wonder if there’s anything we can do for this? How common is it for computer users who don’t rely on assistive technology to have to run the same site through multiple browsers to read it effectively? Currently there are weird bugs in some browser screen reader combinations where certain page elements are not read or read incompletely. The only way you know when things are read wrong on some pages is to use another screen reader, or the same screen reader with another browser. This tends to mostly affect CSS or forms, but probably affects other javascript and things. I’m not a web developer, but I could learn if someone thought it’d help. Standards are often ignored anyway, just like legislation. Having a standard doesn’t really help. If someone wants to customize the heck out of their system, they will, and you can’t test every case. Part of this is up to the user to know how to use the technology, and part of it is the developer having enough compassion to make the best job of writing the pages and code accurately. There’s no standard that you could write that will make someone care about something enough to do it. Legislation of anything is likely to have a negative affect anyway especially among caring people. The other problem is that acccessibiliity means nothing if you don’t need to use it yourself. I hit the same snag once when I wrote a program that didn’t take into account unicode, because I only speak English and have no way to test internationalization. I suspect this happens to developers as well. If they don’t know a screen reader user personally, why would they think to make things accessible? You can’t legislate altruism, which is what this comes down to. Part of the problem with some screen readers is things like NVDA’s “browse mode” which I personally don’t like because it breaks every web app with keyboard shortcuts. I happen to like a lot of keyboard shortcuts. Facebook and Google Music are examples where this is particularly annoying. I have a large music library and I’d have a larger feed possibly if that particular site wasn’t so cumbersome to navigate and use. But built-in screen readers like Narrator and Voiceover don’t receive updates quick enough to keep up with a dynamic web. W3C recommendations can’t move fast enough either. It’d be helpful to include things like Orca and Linux because users of those platforms are more likely to be able to help developers fix a lot of the things that are broken. The worst thing you can do is have screen readers parsing HTML because that’s where most of the trouble starts. We should discourage that practice. A screen reader is supposed to read the screen and leave it up to the user what to do with the data. Probably the place to start is to get operating system makers to expose accessibility API’s in such a way that things like “browse mode” or virtual buffers can never happen. That will get rid of a large class of odd behavior and make sure that the user and the developer both know precisely what markup or code is doing at all times. If this comment is too long or out of place otherwise not helpful, feel free to delete it. Otherwise thank you for reading and I hope the somewhat random and disorganized thoughts might be somehow useful. If you need help testing, I have time and would bother learning web development to help. With so much being on the web, it’d be good to get things to a sane state.
As we know that in CSS3, we have some advanced properties that is used for positioning the elements as well as designing them beautifully. But, usually the designers break the order of content which is visually perfect but not suitable for screen-reader. So, we should prefer using ‘tab-index’ and aria-* attributes.
It’s tempting to use tabindex and ARIA, but this can turn into a real maintenance issue. We regard ARIA as a tool of last resort, for things that HTML can’t do. As for tabindex–we have never seen an implementation of positive tabindex values that didn’t just cause more problems. We advise developers to structure HTML in a logical order and to position that content visually as needed with CSS.
Wouldn’t it be great if there is something like „Browserstack“ but just for screenreader? So you can test different screenreader over different browser (and maybe hardware). 
Does somebody know if there is something like that out there somewhere?
If someone is interested –> contact me and i’ll make a project around that 😉
(p.holz@inovex.de)