Make accessibility great again: почему скринридер не видит ваши таблицы
Глафира Жур провела небольшое исследование и выяснила, как вернуть таблицам доступность после осенних обновлений Chrome.


Кадр: «Сноуден»

Глафира Жур
Accessibility Driven Team Lead в SpurIT Google Developer Expert for Web. Организатор @a11yminsk и @MinskCSS/@MinskJS.
Недавно я обнаружила, что скринридер не читает таблицы в Chrome. При этом они выглядят как таблицы, описаны стандартными табличными HTML-тегами, никаких дополнительных стилей к ним не применяли и не меняли роль. Короче говоря, стандартная структура: table > tbody > (tr > td*3)*3.
В чём суть проблемы

Скриншот: Skillbox Media
Считается, что сделать таблицы доступными можно, соблюдая два основных правила:
1. Задать таблице имя. Например, с помощью <caption> внутри <table> или внешнего лейбла aria-label — специально для программ, читающих с экрана.
2. Задать заголовочную ячейку <th>, чтобы пользователь скринридера понимал, на каком элементе он находится.
Однажды я столкнулась с таким блоком данных:
Open | High |
Close | Low |
Я думала, что он свёрстан при помощи div, поэтому ожидала, что скринридер прочитает ячейки в порядке Open —> Close —> High —> Low. В этом случае первым прозвучал бы div с Open / Close, а потом div с High / Low. Но скринридер прочитал таблицу построчно: Open —> High —> Close —> Low. Получилась какая-то путаница!
Я заглянула в код и увидела, что таблица свёрстана как table — поэтому она и не читалась в ожидаемом порядке. Но возник другой вопрос: почему скринридер не сказал, что читает table? Тогда я проверила роль в Accessibility Tree и нашла role="layouttable"!

Скриншот: Skillbox Media
Откуда взялась role = "layouttable" — в спеке не сказано. Сообщений об апдейте Chrome, связанных с этим параметром, я пока тоже не нашла. И в Firefox такого прикола нет — все таблицы обозначаются как role="table".

Скриншот: Skillbox Media
Как заставить скринридер прочитать таблицу
В результате собственного расследования и благодаря ответу на вопрос в чате Accessibility Community выяснилось, что, если в таблице нет тегов <th>, браузер рассматривает её как layout-таблицу и добавляет role="layouttable". Поэтому скринридер перестаёт её читать как таблицу.
Статья написана на основе треда Глафиры в Twitter.
Кроме того, если у таблицы нет <th>, но атрибутом задана ширина границ (например, border="1") — таблица снова становится table и читается скринридером.

Скриншот: Skillbox Media
Заметьте: если в структуре HTML-документа не установить <th> или border, но задать значение свойства border в CSS — таблица так и останется layouttable.
Вывод: если хотите, чтобы скринридер правильно читал ваши таблицы в Google Chrome, — не забывайте прописывать <th>.
Ещё для <th> полезно выставлять значение атрибута scope "col", если это заголовок столбца, или "row", если заголовок строки.
На webaim.org работа скринридера с таблицами описывается следующим образом:
«Скринридеры анализируют разметку и структуры таблицы, чтобы „угадать“, является ли она data table или layout table. Поэтому очень важно, чтобы элементы разметки data table, такие как <caption> и <th>, НИКОГДА не использовались в layout table».

Скриншот: Skillbox Media
Как подметил @zavsievich в Twitter, если явно задать таблице без <th> role="table", то Chrome будет говорить скринридеру, что перед ним — таблица. Её дочерние элементы будут читаться как нужно, а скринридер сможет правильно по ней перемещаться.