为什么我的屏幕 reader 在激活时不宣布选定的选项卡

Why does my screen reader not announce the selected tab when activated

我正在努力使我现有的选项卡组件可访问,我的设计基于 W3C 的 Example of Tabs with Manual Activation

You can access my demo here

HTML

<div class="tab-container" lang="en">
  <div class="tabs" role="tablist">
    <button class="tab" aria-selected="true" href="#" role="tab" data-tab-name="tab1" tabindex="0">
      <!-- tab name -->
    </button>
    <!-- more tabs -->
  </div>
  <div class="tab-content" data-name="tab1" role="tabpanel" tabindex="0">
    <!-- tab panel content -->
  </div>
  <!-- more tab panels -->
</div>

JQuery

function getTabContent($tabContents, tabName) {
  return $tabContents.filter('[data-name="' + tabName + '"]');
}

function setSelectedTab($tab) {
  var tabName = $tab.data('tab-name'),
      $tabSet = $tab.closest('.tabs'),
      $tabContents = $tab.closest('.tab-container').find('.tab-content');

  // update the tab indices and aria attributes
  $tabSet.find('.tab').attr('aria-selected', 'false').attr('tabindex', '-1');
  $tab.attr('aria-selected', 'true').removeAttr('tabindex');

  $tabContents.addClass('hidden');
  getTabContent($tabContents, tabName).removeClass('hidden');
}

function handleTabSelection(event) {
  var $tab = $(event.target);

  if ($tab.data('tab-name')) {
    event.preventDefault();
    setSelectedTab($tab);
    $tab.focus();
  }
}

// Our tab control needs to be used in many places on our site, we cannot guarantee that all devs will use unique IDs
//   so we need to generate them here
function initTabs($tabContainer) {
  var $tabList = $tabContainer.find('.tabs'),
      $tabContents = $tabContainer.find('.tab-content'),
      tabSetName = $tabList.data.name,
      tabIdPrefix = 'tab-',
      contentIdPrefix = 'tab-content-';

  // add unique ids and labels
  $tabList.children().each(function() {
    var $tab = $(this),
        tabName = $tab.data('tab-name'),
        $tabContent = getTabContent($tabContents, tabName),
        tabId = getUniqueId(tabIdPrefix + tabName),
        contentId = getUniqueId(contentIdPrefix + tabName);
    // add the unique id and associate the link with the content
    $tab.attr('id', tabId).attr('aria-controls', contentId);
    // add the unique id and use the link as the label for the content
    $tabContent.attr('id', contentId).attr('aria-labelledby', tabId);
  });
}

function getUniqueId(id, index) {
  var newId = id;
  if (index) {
    newId += '--' + index;
    index++;
  } else {
    index = 1;
  }
  if (document.getElementById(newId)) {
    return getUniqueId(id, index);
  }
  return newId;
}

function handleKeyPress(event) {
  var $tab = $(event.target);
  if ($tab.is('.tab')) {
    var keyCode = event.which,
        $tab = $(event.target);
    if (keyCode === 13 || keyCode === 32) {
      // user pressed enter, or space
      setSelectedTab($tab);
      event.preventDefault();
    } else if (keyCode === 37 || keyCode === 39) {
      // the user pressed left or right
      var $newTab = $tab[keyCode === 39 ? 'next' : 'prev']();

      // move the focus
      if ($newTab.length > 0) {
        $newTab.focus();
      }
      event.preventDefault();
    }
  }
}

$('.tabs').click(handleTabSelection);
$('.tabs').keyup(handleKeyPress);

$('.tab-container').each(function() {
  initTabs($(this));
});

用户可以使用左右键在选项卡列表中移动焦点,并输入或space到select一个选项卡。

然而,当用户 select 选择一个选项卡时,屏幕 reader 只是宣布 "selected" 在 W3C 的示例中,它宣布选项卡名称后跟 "selected"。

我正在 Firefox 中使用 NVDA 进行测试,以下是我的重现步骤:

  1. 将焦点设置在 "Nils Frahm" 选项卡上
  2. TAB
  3. 你应该听到 "Agnes Obel tab two of three"
  4. 回车
  5. 你应该听到 "Agnes Obel tab selected tab two of three"

这正是 W3C 示例中发生的情况,但在我的示例中,最后一步仅读取 "selected"。

我已经尝试尽可能地匹配他们的示例,但我还没有弄清楚如何让我的示例在激活时宣布选项卡名称。

什么会导致 NVDA 在激活后跳过读取选项卡名称?

我发现了解决问题的方法,但到目前为止,还不知道问题存在的原因。

当我在我选择的选项卡上添加 after CSS 规则时,屏幕 reader 在选择时开始阅读内容。

.tab[aria-selected="true"]::after {
  content: '';
}

如果我将 after 标记添加到所有选项卡,问题仍然存在;它只需要在选定的元素上。

我猜这是在欺骗屏幕 reader 以为内容已更改,因此它会读取新的选项卡名称。

Here is the working demo