背景
有一个手风琴式UI元素形式的常见问题和答案列表:
<h1>Frequently Asked Questions</h1>
<ol class="accordion">
<li>
<h2>
<button type="button" aria-expanded="false" class="accordion-trigger"
aria-controls="question-1-answer" id="question-1">
<span class="accordion-title">What is HTML?</span>
</button>
</h2>
<div id="question-1-answer" role="region" aria-labelledby="question-1"
class="accordion-panel" hidden>HyperText Markup Language</div>
</li>
<li>
<h2>
<button type="button" aria-expanded="false" class="accordion-trigger"
aria-controls="question-2-answer" id="question-2">
<span class="accordion-title">What is CSS?</span>
</button>
</h2>
<div id="question-2-answer" role="region" aria-labelledby="question-1"
class="accordion-panel" hidden>Cascading Style Sheets</div>
</li>
<!-- list divider start -->
<div class="accordion-divider" role="region" aria-labelledby="divider-heading">
<h2 id="divider-heading">Contact us to find out more</h2>
</div>
<!-- list divider end -->
<li>
<h2>
<button type="button" aria-expanded="false" class="accordion-trigger"
aria-controls="question-3-answer" id="question-3">
<span class="accordion-title">What is JS?</span>
</button>
</h2>
<div id="question-3-answer" role="region" aria-labelledby="question-3"
class="accordion-panel" hidden>JavaScript</div>
</li>
</ol>
在元素2和3之间,有一个分隔块,它包含与列表上下文无关的交互式内容(可以想象列表元素之间的广告带有行动按钮调用)。
问题
- 屏幕阅读器(在macOS的VoiceOver上测试)宣布列表包含4个项目,而应该有3个项目和一个分隔块
- 屏幕阅读器应将分隔块宣布为列表中的独立内容
问题
- 如何以可访问的方式描述分隔块,以便屏幕读取器正确地宣布它
- 也许有一种更好的方法可以在语义上和可访问性上描述带有分隔块的有序手风琴列表
我已经尝试了什么
我已经在分隔块上尝试了几个WAI-ARIA角色(如region
和separator
),但屏幕阅读器总是将分隔块作为列表的一部分。
您没有有效的HTML。获取语义正确的HTML以使其可访问已经够难的了,但当您拥有无效的HTML时,这几乎是不可能的。
列表规范规定<ol>
只能将<li>
元素作为直接子元素。将<div>
作为<ol>
的子级会混淆浏览器和屏幕阅读器。不能在列表项的中间有一个非列表项。
如果你真的想让某个东西看起来像列表中间有一个块,我可以想到两个三个四件事要做:
-
在列表项的末尾(或开头)插入块,这样它在视觉上看起来不是列表的一部分,但实际上是。我认为这仍然会让屏幕阅读器用户感到困惑,因为很难找到块
-
在DOM中的列表之前或之后具有块,但使用CSS来移动它";内部";列表。该块实际上是";在顶部";(如在
z-index
中),而不是真正的";内部"; -
我想第三种选择是回到设计师那里,问你为什么要在列表中间放一个块。
-
最后,这应该能真正解决你的问题,创建一个包含两个项目的列表(或者在块之前需要多少),然后关闭列表并进行块然后将您的第三个列表项创建为独立列表项,并将您的第一个列表指向此";孤儿;通过
aria-owns
列出项目。
通过设置role="presentation"
创建孤立列表,但让第一个列表拥有第二个列表的项目的所有权。
您需要将role="listitem"
重新添加回列表项,因为父项的role="presentation"
使列表项成为表示元素,因为role="presentation"
向下传播到子项。参见role="presentation"
的规范,特别是:
当显式。。。演示的作用被应用于一个元素。。。具有必需的所属元素,除了具有显式演示角色的元素外,用户代理必须将继承的演示角色应用于任何未定义显式角色的所属元件。
也就是说,在列表上设置role="presentation"
也会将role="presentation"
应用于列表项(拥有的元素)。
<ol aria-owns="orphan">
<li>...What is HTML...</li>
<li>...What is CSS...</li>
</ol>
<!-- block of stuff -->
Contact us
<!-- block of stuff -->
<ol role="presentation">
<li role="listitem" id="orphan">...What is JS...</li>
</ol>
如果您希望孤立列表继续使用第一个列表中的数字,则可能必须使用CSScounter()
和counter-increment
。
如果您将列表和块放在其中,正如已经指出的,不能在列表的中间有独立的内容,而这些内容实际上并不是列表的一部分。因此,在任何情况下,你都需要处理一些奇怪的事情:
- 除非你使用咏叹调大小/咏叹调位置集,否则太多的项目将被宣布为项目总数,但从长远来看,保持这两个属性的正确性很快就会发生变化,而不是说你应该尽可能避免使用aria,在那里,你可以通过另一种方式轻松避免
- 没有简单的方法可以让列表跳过计数中的一个项目,除非使用CSS计数器,但CSS生成的内容并不总是由屏幕阅读器宣布
- 您可以将列表拆分为两个单独的列表,但在这种情况下,屏幕阅读器用户不会知道项目的总数,您需要再次使用一些技巧来正确计数
事实上,HTML列表并没有被设计成在中间被打破,并且没有办法说两个列表必须连接在一起。那些只想在多列中显示项目列表的人也有同样的问题。
因此,到目前为止最好的当然是不要打破名单。
可悲的是,我认为市场营销人员比为无障碍服务的人更有决策权。
然而,从语义上讲,我不确定在FAQ示例中是否真的需要一个有序列表。将每个问题放在一个标题中可以提供足够的导航。按标题导航使其非常简单,并且为屏幕阅读器用户所熟知。_对我来说,把整件事都写在一个列表里似乎是多余的,当然,除非问题数字真的很重要。