代码之家  ›  专栏  ›  技术社区  ›  Godwin

为什么屏幕阅读器在激活时不宣布所选选项卡

  •  2
  • Godwin  · 技术社区  · 7 年前

    我正在努力使我现有的选项卡组件可访问,我的设计基于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));
    });
    

    用户可以使用左右键在选项卡列表中移动焦点,并输入或空格选择选项卡。

    然而,当用户选择一个选项卡时,屏幕阅读器只会宣布“selected”,在W3C的示例中,它会宣布选项卡名称,后跟“selected”。

    我正在Firefox中使用NVDA进行测试,下面是我复制的步骤:

    1. 将焦点设置在“Nils Frahm”选项卡上
    2. 桌棋类游戏
    3. 你应该听“阿格尼丝·奥贝尔三张二张”
    4. 输入
    5. 你应该听到“Agnes Obel tab selected tab two of three”

    这正是W3C示例中发生的情况,但在我的示例中,最后一步只显示“selected”。

    我试图尽可能地匹配他们的示例,但我还没有想出如何让我的示例在激活时宣布选项卡名称。

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

    1 回复  |  直到 7 年前
        1
  •  -1
  •   Godwin    7 年前

    我发现了如何解决问题,但到目前为止,还没有发现问题存在的原因。

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

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

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

    我的猜测是,这是在愚弄屏幕阅读器,使其认为内容已更改,因此它会读取新的选项卡名称。

    Here is the working demo