Tables, CSS Display Properties, and ARIA
This post has two separate but related things going on. One is an example of one of my responsive tables with ARIA added, and the other is the Twitter conversation that started this along with some generalized responses.
Responsive Table with Semantics Retained by ARIA
See the Pen Responsive Table with Semantics Retained by ARIA by Adrian Roselli (@aardrian) on CodePen.
This example (viewable directly at CodePen) shows how you can use ARIA table roles to override / re-insert the table semantics you may lose by using CSS flex or grid.
First, you need to understand how to use the roles, including getting the nesting right. In general these can be simple. The table
role should be added to the <table>
element. If you use <thead>
, <tbody>
, and/or <tfoot>
, they get the rowgroup
role. <tr>
gets row
and <td>
gets cell
. <th scope="col">
gets columnheader
while <th scope="row">
gets rowheader
.
It really is that straightforward.
But here is where it gets complicated. Tables that hide content (especially headers) in a responsive or similar context, and tables that re-order content.
The re-ordering issue is easy to solve — don’t use CSS to re-order table content. Use client-side script to move the nodes around in the DOM. For example, using CSS flex or grid to sort a table may be novel, but it will not support screen reader users.
Hiding content is a bit trickier. My example above addresses that. It uses the same code as my responsive accessible table, but with two differences. It now has the ARIA roles I outlined above, and it does not add the replacement text for the row headers until you click the button. The button is only there to give you a chance to experience the table without the replacement text (in a narrow view).
Examples
The following videos demonstrate how the ARIA can make the table semantics, and thus table navigation, work within the browser. The first one demonstrates how the hidden column headers hurt our ability to understand the narrow table (not just visually). The second video demonstrates how the table is more understandable once the generated content appears to take the place of the hidden column headers.
Advice
If you are not able to test with a screen reader, maybe don’t do this. You run the risk of making an already problematic responsive table downright unusable. Further, if you are not going to test regularly as browsers and screen readers get updated, maybe don’t do this.
The Tweet
I pushed out a tweet yesterday that generated a lot of interesting questions and conversations. I think it may have also led to some confusion.
Using CSS flex on a <table> overrides its native semantics, rendering it useless to a screen reader. Avoid.adrianroselli.com/2015/10/html-s…
I followed it up to add some detail:
I should add, using display: block | grid | inline | … on table elements will also override native semantics. Not unique to flex.
Collected Responses
I received some interesting questions and comments, some of them tinged with frustration. The most critical thing I learned is that developers who play around with CSS and tables on the whole do not test them in screen readers. This is my effort to break down the types of questions and comments and provide some extra information.
- Developers have been breaking HTML table semantics via display properties since before CSS flex and grid.
- This should not make it harder / impossible to make responsive tables. I wrote some easy and less easy ways to make responsive tables.
- CSS already has as impact on HTML semantics —
display: none
is an example of that. - If screen readers give priority to mark-up over styling in every instance, then
display: none
would no longer work. - Setting
display: table
and related does not impart HTML table semantics to (<div>
) layouts that used it for things like vertical centering. - This is not a function of screen readers alone, as they get their accessibility information from the browser.
- A screen reader needs more than the DOM to understand a page, so asking it to ignore all but the DOM is impractical.
- Users don’t want us to be able to detect screen readers, nor should we and certainly not as a workaround for responsive tables.
- Even if you could detect screen readers, how would you know which third of those users are not blind?
- Even if you listen for mouse actions as a proxy for sighted screen reader users, how do you account for those with mobility impairments who do not use a mouse? Or mobile screen reader users who rely on touch gestures?
- Disabling a site’s CSS for screen reader users is therefore impractical (and a terrible, terrible idea).
- Using flex or grid for an HTML table already means you are running the risk of messing up content order versus source order (not unique to tables).
- Using CSS grid to lay out an HTML table may be fine, but it still won’t be a table semantically
- A significant part of why we have this situation is because of years of relying on HTML tables for layout that had their display properties tweaked, providing a cue to screen readers that they were for layout only.
- Screen readers already have their own heuristics for dealing with tables, primarily due to years of poor developer practices, with current behaviors tracked by PowerMapper.
- While ARIA provides roles for tables, it requires you to understand your tables well and stay on top of screen reader testing as new releases come.
- Applying ARIA roles to retain table semantics can be problematic for responsive tables where header cells or other cells are discarded, a common pattern in responsive table examples. See the previous section of this post.
- Generally, do not use ARIA to try to override CSS, not just because the CSS may not load, but because this is not the purpose of ARIA.
If you find the ability to so casually dismiss HTML table semantics to be frustrating, it is not the fault of screen readers. It is the fault of years of terrible coding practices predicated on visual layout over developer rigor of choosing the right element for the job.
If you find you want to use CSS flex, grid, block, inline, or other display properties on a table, then maybe consider what the heck you are doing with the table.
Assorted CSS Specifications
I may have stayed up too late trying to parse all this.
CSS 2.x tries to break down the role of CSS for tables, namely leaving it up to HTML to define the semantics:
Table layout can be used to represent tabular relationships between data. Authors specify these relationships in the document language and can specify their presentation using CSS 2.1.
CSS 2.x also accounts for non-HTML pages, where it adds the semantics and generates the necessary anonymous table objects around itself:
In other document languages (such as XML applications), there may not be pre-defined table elements. Therefore, CSS 2.2 allows authors to “map” document language elements to table elements via the ‘display’ property. For example, the following rule makes the FOO element act like an HTML TABLE element and the BAR element act like a CAPTION element:
I can find nowhere in the CSS 2.x specification (specifically in the visual formatting model) where the display
property should override the native semantics of the source document language (HTML).
The closest statement about interaction with tables that I can find in the Flexbox specification is a note directed at user agent makers, and says nothing about changing the semantics:
Note: Some values of display normally trigger the creation of anonymous boxes around the original box. If such a box is a flex item, it is blockified first, and so anonymous box creation will not happen. For example, two contiguous flex items with display: table-cell will become two separate display: block flex items, instead of being wrapped into a single anonymous table.
CSS Grid has similar language:
Note: Some values of display normally trigger the creation of anonymous boxes around the original box. If such a box is a grid item, it is blockified first, and so anonymous box creation will not happen. For example, two contiguous grid items with display: table-cell will become two separate display: block grid items, instead of being wrapped into a single anonymous table.
In short, I can see nowhere in the CSS, grid, nor flex specifications where a user agent should override the native semantics of the source document language (HTML). Based on that, my read is that browsers dumping table semantics is a bug.
Example
I made videos with a screen reader to try to demonstrate how you can ruin the ability to navigate and parse a table just by adding flex.
What You Can Do
Help purge the web of layout tables. Help purge the web of CSS table display properties just for vertical centering. Code tables properly and accessibly.
In conjunction with that, file issues against web browsers. Browsers parse the page and then hand it off to a screen reader. If you can get the browsers to behave consistently, then you can get screen readers to adapt as well, as they may no longer need to rely on heuristics to protect users from bad code.
In the meantime, test your responsive tables with screen readers.
Maybe weigh in on the discussion [Proposal] new attribute for specifying focus and reading order at WICG Discourse.
Update: March 3, 2018
Roger Johansson wrote a piece in 2011 that wraps up both how browsers destroy semantics on tables and lists when CSS display properties are applied: Screen readers and CSS
Update: March 4, 2018
This quote from Steve Faulkner’s post Short note on what CSS display properties do to table semantics nails it (it being who is to blame for this mess):
[I]t’s either wittingly/unwittingly the fault of the developer or the browser. But what we can be sure of, in these cases, is that it is not the fault of the screen reader.
Update: March 27, 2018
It is worth noting that display: contents
on a <table>
, <ul>
, <ol>
, etc. also hides it from screen readers. Granted, it’s late and I only tested in Firefox and NVDA so far, but you can try it out yourself (embedded below or visit it directly at CodePen):
See the Pen Table with display:contents by Adrian Roselli (@aardrian) on CodePen.
Read Ire Aderinokun’s post, How display: contents; Works for other ways display: contents
can affect content on a page.
Update: February 19, 2020
Big progress. Chrome 80 no longer drops semantics for HTML tables when the display
properties flex
, grid
, inline-block
, or contents
are used. The new Edge (ChromiEdge) follows suit. Firefox still dumps table semantics for only display: contents
. Safari dumps table semantics for everything.
Chrome v80 no longer dumps table semantics when CSS flex is applied.
Test: cdpn.io/aardrian/debug/xxGEKKJ
Not only display property impact parity with Firefox, but passes Firefox (since display: contents still eats table semantics in Firefox but no longer in Chrome). pic.twitter.com/4iuitwgWhS
Update: September 29, 2020
Léonie Watson has just posted How screen readers navigate data tables where she walks through a sample table to get some information, explaining each step, the keyboard commands, and the output. She also links to a video demonstration, which I have embedded below.
Update: December 7, 2022
I should have linked to my updated post sooner: It’s Mid-2022 and Browsers (Mostly Safari) Still Break Accessibility via Display Properties
Chrome is fine now, the last Firefox bug just closed and should deploy soon, and Safari is still a hot mess after repeated assurances it was being fixed.
20 Comments
The videos would be a better demonstration if anyone not used to a screenreader would understand them. I doubt that there are many, not used to screenreaders, could understand anything in that speed. Could you provide thos videos in a slower speed? The actual speed must be 6x or 8x speed :-)
In response to .Jens, I am on a deadline, so I won’t be re-making these videos in the short term. In the meantime, I suggest viewing this page in Edge or Firefox, which allows you to watch a video at half speed. I wrote some details on this feature in a post.
Hi Adrian, thanks for the suggestion. Would have been nice, but the quality of the half-speed video is worse. I cannot understand anything. Well it was an idea. Ignore my plea from the first comment. Nevertheless an interesting finding although anyone not used to a screen reader won’t understand anything.
I keep the fingers crossed for your deadline :-)
Setting display: table and related does not impart HTML table semantics to (
<div>
) layouts that used it for things like vertical centering.Help purge the web of CSS table display properties just for vertical centering.
Aren’t these statements kind of contradicting each other? If using table
display
on non-table elements is not meant to give them table semantics (and web devs have been taught for years that it doesn’t, and consciously use it for visual-only layout tweaks!) — why should we stop using it just because some software erroneously treats such elements as real tables, contrary to the common developers expectations (according to the data collected in the corresponding Firefox bug, currently fixed)? The section 4.9.1 of both HTML specs also has a note directly suggesting using CSS table model as one of the alternatives to (ab)using HTML tables for layout. Why should the browser/AT incapability to distinguish the semantically wrong HTML layout and the semantically correct DOM with some visual-only tweaks for minor layout enhancement be the problem of web devs who consciously use HTML to express semantics and CSS just to present it nicely in certain circumstances, not of the developers of these browsers/AT who should improve their heuristics to match the web devs intentions better?If you find you want to use CSS flex, grid, block, inline, or other display properties on a table, then maybe consider what the heck you are doing with the table.
Unfortunately, not all design requirements can be currently reasonably met with CSS table model. The simplest example from my recent experience is fitting the whole table into the container width (wrapping the sell text if necessary) while having one column shrink-wrap to its longest content.
Table-layout: fixed
can do the former,table-layout: auto
can do the latter, but neither can do both. Grid layout (accompanied withdisplay: contents
for table rows) would solve it.I agree that limiting ATs to DOM only is impractical and the problem is more complicated than one might think at first glance. But just prohibiting web devs to use certain CSS features seems not to be a long-term solution to me. I guess we should gather stats of how these features are really used and what web devs are meaning by them, collect the feedback of actual ATs users which behavior is helpful for them and which is not, and file bugs to browsers and ATs if necessary — as it seemed to work in Firefox case above…
In response to .
Aren’t these statements kind of contradicting each other?No. The first statement describes where we are today. The second statement is a plea to hopefully help make it easier for heuristics to make better guesses (by not abusing the intent of the CSS
display
property).Related, there is a Firefox bug that changing the
display
property of a<table>
blows away its semantics. It is still open. The bug you cited (and which was resolved) was about the addition of table semantics to non-<table>
elements just becausedisplay: table
is added. They both need to be addressed to prevent the issues we are experiencing.You ask why this should be the problem of web developers, and I answer that it is our job. It has always been our job. We are supposed to make things work for our users and file bugs when the specs and browsers get it wrong.
Let me try a heavy-handed analogy — it should be up to municipalities to fix potholes on their roads so car makers do not have to install shocks. So let’s build cars with no shocks. That will force municipalities to fix their roads.
Unfortunately, not all design requirements can be currently reasonably met with CSS table modelI have never needed to use CSS table layout in a project, after building easily hundreds of sites and applications. As a result, I struggle to understand the limitations of CSS table layout since it was never part of my process. My suggestion above is an effort to simplify the heuristics that browsers use to decide what is and isn’t a data table.
I am also suggesting not overriding real HTML tables with CSS
display
properties, both to developers and browsers.
In response to .Adrian, thanks for your reply!
But I’m still a bit confused about the first statement: doesn’t it turn out that
display:table/table-cell
does affect the semantics of the‹div›
element (at least in Chrome)? Or do you suggest that changing the semantics of the element by just changing its styling is OK? If so, than, using your cars/roads analogy, this sounds to me like “the potholes are OK, people who complain about them are only trying to save on shocks in the cars they build”. For me, it’s kind of false dichotomy: what car users really want is probably to drive in the cars with good shocks on the roads with no potholes:)The Firefox issue about tables loosing their semantics because of the `display` value is filed as a bug — yet open, but still a bug, not a feature, not “resolved wontfix”. I agree that it may be hard to decouple the semantics from the visual layout (they are called “screen readers”, after all!). But… being unable to use a proper markup to express the intended meaning and visually enhance it with advanced layout tools because browsers can’t treat it as intended because their heuristics are optimized for the old messy markup feels kind of unjust. It’s like people who consciously follow the HTML spec recommendation get punished for the sins of the ancient web coders who had no idea what they were doing.
I agree that currently we should avoid overriding the native
display
, as it’s really problematic, and by no means call for “building cars with no shocks”:). But I don’t want this situation to last forever. I hope this second Firefox bug will be resolved at some point, as well as similar bugs for other browsers (if they are not filed yet, they should be). Screen readers shouldn’t drop the table semantics from something that is marked up properly as a data table, visually looks like a nice data table and quacks like a data table, just because it doesn’t use the “magic” CSS value for itsdisplay
. The less such implicit “magic” would be there in the platform at all, the simpler would be the browser heuristics, and the easier it would be for web devs to create the best experience for all the users. Of course, we need some stats first, how much existing content relies on that “magic” — but I hope it’s not really that much of it.I also couldn’t find any place in CSS specs saying anything about influence of CSS display to the meaning. The only place where CSS is mentioned as a possible indicator of table meaning seems to be the HTML spec saying that “Explicit visible borders set using CSS” mean that a table is “Probably a non-layout table”. But the introduction section in the CSS Display spec draft has a note mentioning that
display
can interact with the speech output, and links to the CSS Speech module (though very outdated). Maybe the CSS Display module is the best place to clarify this issue as well?
In response to .
doesn’t it turn out thatdisplay:table/table-cell
does affect the semantics of the<div>
element (at least in Chrome)?No. Check the Chrome accessibility inspector. It is just a generic container.
Or do you suggest that changing the semantics of the element by just changing its styling is OK?No. Since much of the rest of your response is predicated on one or both of those being yes, I’ll just tackle specific points you make.
It’s like people who consciously follow the HTML spec recommendation get punished for the sins of the ancient web coders who had no idea what they were doing.Much of HTML 5 was built to reflect current and historic practice. If anything, the spec is the result of those earlier coders.
I hope this second Firefox bug will be resolved at some point, as well as similar bugs for other browsers (if they are not filed yet, they should be).You can contribute by looking for open issues and posting your concerns, and when those issues do not exist, filing them.
Maybe the CSS Display module is the best place to clarify this issue as well?I see some new bug filings in your future!
Tables are probably toughest to make responsive. Most approaches we tried were based on div / span – however it has its own trade off.
I like this approach better. Though, some issues I see are minor.
Can we not assume role=’row’ for any tr ? I am not feeling comfortable with the redundancy of calling it tr and role both where it can be inferred.
In response to .You can experiment with removing the
role
from<tr>
and testing it with more screen reader / browser combinations. I agree, I do not like having to add them either.
In response to .Toughest part for me right now is to debug these stylings and JS issues in iOS devices. For most part safari does help, however when it does not work – it does not work and frustrates me to hell.
May be I have not come across a better tool to debug CSS / JS in actual devices. Browser addons have kind of spoiled my creativity I guess.
I would like to know how do u debug these one of device specific issues that wont happen on a simulator.
In response to .Just to give more context on a sample issue I am currently struggling. It is actually JS issue but cant debug it –
I wrote this simple math practice tool for my kid to learn math tables.
obviously it had to be responsive so I picked a template that worked pretty well for styling part. But my JS seems to not work on iPad
it works on safari with ipad user agent.
http://math.imustread.com/multiplication/practice.html
this is open source on github here
https://github.com/fromdev/math/blob/master/multiplication/practice.html
In response to .Short of getting your hands on a device and running a remote debugger, there isn’t much help I can offer on testing on your iPad. A Google search brought me to this set of instructions for remote debugging. It is from 2014 but updated a few days ago.
Hi Adrian,
It’s Teddy again. Just noticed that Voiceover on my iPhone isn’t recognizing the ARIA table as a data table and doesn’t read the caption, but it does read the rest of the table’s contents.
Whereas it was the opposite with your previous no-ARIA semantic table, recognized the table, read the caption, but couldn’t read the rest of the table.
Update: This is marked as fixed in Firefox 62. Just checked Steve’s test case in the accessibility tree and in NVDA and it looks fixed indeed, for display:block.
For Flex and Grid the table is identified as such, but table nav is broken.
In Chrome + NVDA all the non-default tables are just skipped.
Setting
display: table
and related does not impart HTML table semantics to (<div>
) layouts that used it for things like vertical centering.For Safari + VoiceOver on iOS specifically, this does incorrectly announce
table
semantics in the form of, “Table start…” and “Table end…”Recommended to use Flexbox instead for layout.
In response to .Thanks, Scott. The note and demo are helpful.
[…] Tables, CSS Display Properties, and ARIA | Adrian Roselli – More on responsive, accessible tables with ARIA […]
Thanks for the good article. Do we know if FF or Safari have stopped dumping table semantics when CSS
display
is applied?
In response to .Firefox 94 seems fine. My Mac is [waves arm] over there, so I cannot check it right now. However, if you take the embedded pen from above and inspect the accessibility properties you can confirm support (or lack). As for when this was fixed, you can dig into the issue history for specific release. Either way, things are much better now then they were 3½ years ago.
Just found the article. It was very helpful. Big thank for updating it.
Leave a Comment or Response