为什么在使用屏幕 reader 浏览 header 时总是读取上方的 header 按钮?

Why when navigating through the header with the screen reader the upper header buttons are always read?

我的问题是我正在尝试使某些 table 更易于访问,但我遇到了一个非常奇怪的问题,我尝试了多种解决方案但无济于事。我从这张截图中得到了这个 table:

如您所见,当我查看每个 header(如 CSLO、开始日期等)时,它会从上方读取 header。因此,每次我使用选项卡或箭头控件关注任何 header 名称时,它也会从上方读取两个按钮。

我试过将按钮分开,使用不同的角色,取出 类 等,但我真的没有指出为什么它总是触发按钮,即使它们没有聚焦。

它的代码是这样的:

<table
  class="table table-bordered table-hover component-editable slolisting dataTable ui-sortable"
  data-editable-id="slo-list-237"
  id="DataTables_Table_0"
  style="display: table"
>
  <thead>
    <tr class="header_action" role="row">
      <th rowspan="1" colspan="1">
        <div class="btn-group checkall-actions">
          <label
            class="btn btn-default component-editable-checkall"
            onclick="component.editable.select_all_rows(event, this);"
          >
            &nbsp;<input type="checkbox" />&nbsp;
          </label>
        </div>
      </th>
      <th colspan="7" rowspan="1">
        <div
          class="btn-group unfocus-actions"
          style="display: inline-block"
        >
          <button
            class="btn btn-primary"
            onclick="creating_init(event, this);"
          >
            Add CSLO
          </button>

          <button
            class="btn btn-default"
            onclick="showModalSyncCSLO('MATH100 - Mathematics for General Education','237');"
          >
            CSLO Synchronization
          </button>
        </div>
      </th>
    </tr>

    <tr class="header_title" role="row">
      <th
        rowspan="2"
        style="width: 60px"
        class="sorting_disabled component-editable-multi-selector-row"
        role="columnheader"
        colspan="1"
      ></th>
      <th
        rowspan="2"
        style="width: 40em"
        class="sorting_disabled"
        role="columnheader"
        colspan="1"
      >
        CSLO
      </th>
      <th
        rowspan="2"
        class="sorting_disabled"
        role="columnheader"
        colspan="1"
      >
        Start Date
      </th>
      <th
        rowspan="2"
        class="sorting_disabled"
        role="columnheader"
        colspan="1"
      >
        End Date
      </th>
      <th colspan="2" class="slo" rowspan="1">
        SLO Performance
      </th>
    </tr>
    <tr class="header_title" role="row">
      <th
        class="slo sorting_disabled"
        role="columnheader"
        rowspan="1"
        colspan="1"
      >
        Expected
      </th>
      <th
        class="slo sorting_disabled"
        role="columnheader"
        rowspan="1"
        colspan="1"
      >
        Fall 2020
      </th>
    </tr>
  </thead>

有趣的是,这只发生在某些屏幕阅读器上,例如 Chrome 上的 NVDA。

导航 table 时,屏幕 reader 将自动读取列和(如果适用)行 header。

当您将两个按钮放置在这些行中时,它们每次都会被读出。这也是因为您将它们全部设置为 <th> 个元素。

您可以将这些按钮移到 table 之外,并将复选框移动到 select 列的下一行(与 CSLO、开始日期等相同的行)。

这将解决问题。

或者您可以使用 <col><colgroup>

您可能还想研究使用 <col><colgroup> 元素定义您的列。这有助于屏幕 readers 正确关联 multi-row headers.

有个great article on how to use these from W3C with plenty of examples and here is a great article on MDN about <col> and <colspan>.

你可能仍然会看到按钮被宣布(你可以把它们放在 <td> 中,虽然从技术上讲这不是一个好的做法,但它应该停止宣布问题并且不影响可用性....你会在屏幕上测试 reader 虽然我从未尝试过,但可以肯定!)

其他几个小问题

您当前的 table 中不需要 role="row"role="columnheader",默认情况下,<tr><th> 已经具有这些角色,假设您支持IE8+.

您可以删除 rowspan="1"colspan="1" - 默认情况下,单元格的大小为 1 行 1 列,因此这是不需要的信息(与可访问性无关,它只会使您的标记更容易读)。覆盖跨度时只需添加 rowspancolspan