如何解决Apple VoiceOver重复朗读含多元素标题的问题?
<i>元素时VoiceOver重复朗读的解决方法 问题场景
在做无障碍优化时发现,当<h2>这类标题标签里嵌套<i>元素时,Apple VoiceOver会出现异常朗读行为:
- 正常情况(无
<i>):
<html> <body> <h2>Buy our awesome product!</h2> </body> </html>
VoiceOver会正确朗读:"heading level 2, Buy our awesome product"
- 异常情况(含
<i>):
<html> <body> <h2>Buy our <i>awesome</i> product!</h2> </body> </html>
VoiceOver会错误朗读成:"heading level 2, 3 items, Buy our... awesome... product... Buy our... awesome... product"——不仅多了"3 items"的提示,还会在元素间停顿,甚至重复整段标题。
该问题仅出现在标题元素中,<p>等段落标签嵌套子元素时无异常,Chrome和Safari浏览器均存在此问题,优先寻求HTML/CSS解决方案,避免使用JavaScript。
可行解决方案
1. 用CSS类代替<i>标签(最推荐)
直接把<i>换成带样式的<span>,避免标题里嵌套语义标签导致VoiceOver把内容拆成多个节点:
<style> .italic-text { font-style: italic; } </style> <html> <body> <h2>Buy our <span class="italic-text">awesome</span> product!</h2> </body> </html>
视觉效果和原代码完全一致,同时VoiceOver会将标题视为单一文本块,正常朗读。
2. 用aria-label指定朗读文本+隐藏<i>的语义节点
如果必须保留<i>的语义(比如标记外来词、专业术语),可以给标题添加aria-label指定完整朗读内容,同时让<i>在无障碍树中隐藏:
<html> <body> <h2 aria-label="Buy our awesome product!"> Buy our <i aria-hidden="true">awesome</i> product! </h2> </body> </html>
VoiceOver会优先读取aria-label中的完整文本,视觉上的斜体效果不受影响。
3. 用role="text"强制合并文本节点
把标题内的所有内容用带role="text"的<span>包裹,让VoiceOver将它们识别为一个整体:
<html> <body> <h2> <span role="text">Buy our <i>awesome</i> product!</span> </h2> </body> </html>
该方法依赖浏览器对role="text"的支持,目前主流浏览器均能兼容。
原理说明
标题元素内嵌套子元素时,VoiceOver会将每个子元素视为独立的可访问节点,导致重复遍历整个标题内容。上述方案的核心是通过不同方式,让屏幕阅读器将标题内容识别为单一连续文本,避免节点拆分引发的重复朗读问题。
内容的提问来源于stack exchange,提问作者Mark Eting

