尽管组件的功能随屏幕尺寸而变化,但如何在组件内保持良好的可访问性?

How can I maintain good accessibility within a component despite its functionality changing with screen size?

我目前正在构建一个由三个无序列表组成的响应式组件,每个列表都有一个关联的标题。代码看起来像这样:

<div>
  <section aria-labelledby="heading1">
    <h3 id="heading1" data-state="open">Heading 1</h3>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
  </section>
  <section aria-labelledby="heading2">
    <h3 id="heading2" data-state="open">Heading 2</h3>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
  </section>
  <section aria-labelledby="heading3">
    <h3 id="heading3" data-state="open">Heading 3</h3>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
  </section>
</div>

在较大的屏幕上,CSS 将其呈现为三列,而在较小的屏幕上,它变成手风琴,点击标题将切换相邻列表的显示。 open/close 功能由 Javascript 处理,只是在打开和关闭之间切换数据状态。

这一切都很好,但在可访问性方面我有点难过。我想告诉辅助技术标题是按钮(使用 role="button" 或将标题文本包装在按钮元素中),但这只有在显示为手风琴时才是正确的。在 three-column 模式下,标题不应该是按钮,只是标题。

如有任何帮助,我们将不胜感激!

所以 DOM 保持不变?没有在响应式视图中添加额外的 HTML 元素?

如果是这样,那就有点棘手了,但您可以使用 Accordion Design Pattern,然后在全屏模式下调整元素的属性。

手风琴包括:

  • 手风琴元素 – collection 面板包含在外面板(通常是列表)
  • Accordion header – 可扩展和可折叠的手风琴面板的标记区域
  • 手风琴面板 – 包含特定于每个 header
  • 的内容的区域(容器)

每个手风琴的标题 header 包含在 <button> 或带有 role="button" 的元素中。

每个手风琴 header 按钮都包装在一个 <hX> 元素中,其级别适合页面的信息架构。按钮元素是标题元素中的唯一元素。

如果与手风琴 header 关联的手风琴面板可见,则 header 按钮元素 aria-expanded 设置为 "true" .如果面板不可见,aria-expanded 设置为 "false"。面板本身应适当设置 aria-hidden 或使用 CSS (display:none) 隐藏。

手风琴面板有 role="region"aria-labelledby,其值引用控制面板显示的按钮。

这与您发布的代码非常接近。您的列表 (<section>) 有一个容器,其中有一个 default role of region,您通过将其指向标题来标记该部分。

因此,一旦您有了手风琴代码,当显示只是一个简单的三列列表时,您就可以决定不需要该结构的哪些部分。

<!-- main accordion container -->
<div>
  <h2>
    <button aria-expanded="false" id="accordion1id">first accordion section</button>
  </h2>  
  <section aria-labelledby="accordion1id">
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>    
  </section>
  <h2>
    <button aria-expanded="false" id="accordion2id">second accordion section</button>
  </h2>  
  <section aria-labelledby="accordion2id">
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>    
  </section>
</div>

这非常接近您的原始代码。当您只需要列表结构(桌面视图)时,您应该能够将 role="presentation" 添加到所有 <button> 元素,这将删除元素的“按钮性”并将它们基本上变成纯文本所以所有您剩下的是带有 child 文本的标题。屏幕 reader 只会知道有一个标题后跟一个带有嵌入列表的部分。

您也应该从按钮中删除 aria-expanded,因为该属性只对按钮有效,对纯文本元素无效。

如果需要,您还可以删除 <section> 上的 aria-labelledby,这会删除这些元素的 landmark 角色,这样它们就会被屏幕忽略 reader也是。代码看起来像这样:

<!-- main accordion container -->
<div>
  <h2>
    <button role="presentation" id="accordion1id">first accordion section</button>
  </h2>  
  <section>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>    
  </section>
  <h2>
    <button role="presentation" id="accordion2id">second accordion section</button>
  </h2>  
  <section>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>    
  </section>
</div>

屏幕 reader 实际看到的是:

<div>
  <h2>
    first accordion section
  </h2>  
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </ul>    
  <h2>
    second accordion section
  </h2>  
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </ul>    
</div>

更新

谢谢,@Robin,你是对的。 ARIA 属性只是 提示 辅助技术,不会影响 行为 因此将 role="presentation" 添加到 <button>,虽然它确实使按钮不再宣布为按钮,但这不会阻止用户跳转到它或单击它,因此您需要在按钮上 tabindex="-1" 以防止跳转,并且您需要将按钮上的事件处理为 NO-OPs。您可能还需要应用 CSS,这样按钮看起来也不像按钮。这一切都是可行的,但有时更容易换入和换出不同的组件。