NVDA/JAWS浏览模式姓名朗读优化及焦点逻辑技术咨询
现有代码
CSS
.ProfileSubHeadTitleLinkStyle-181 { display: flex; margin-top: 36px; margin-right: 20px; margin-bottom: 24px; justify-content: space-between; } .ProfileSubHeadTitleStyle-182 { font-size: 18px; font-weight: 600; margin: 0px 20px 0px 0px; padding: 0px; } .ProfileEditLinkStyle-283 { font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; font-size: inherit; font-weight: inherit; color: rgb(92, 27, 134); outline: none; text-decoration: none; background: none transparent; border-top: none; border-right: none; border-left: none; border-image: initial; cursor: pointer; display: flex; margin: 0px 10px; overflow: inherit; padding: 0px; text-align: left; text-overflow: inherit; border-bottom: 1px solid transparent; align-items: center; user-select: text; } .profileNameColStyle-282 { margin: 20px 0px; display: flex; flex-flow: row wrap; } .flex1-185 { margin-right: 30px; margin-bottom: 15px; }
HTML
<div id="profileNameWrapper"> <div> <div class="ProfileSubHeadTitleLinkStyle-181"> <h3 class="ProfileSubHeadTitleStyle-182">Name</h3> <button type="button" data-testid="edit-link-test-id" class="ms-Link ProfileEditLinkStyle-283"> <i data-icon-name="Edit" aria-hidden="true" class="root-286"></i> Edit </button> </div> <div> <div class="profileNameColStyle-282" aria-hidden="true"> <div class="flex1-185"> <div class="ProfileSubContentTitleStyle-184">First name</div> <div class="ProfileContentStyle-179">Sarfraj</div> </div> <div class="flex1-185"> <div class="ProfileSubContentTitleStyle-184" data-testid="middle-name-test-id">Middle name</div> <div class="ProfileContentStyle-179">L</div> </div> <div class="flex1-185"> <div class="ProfileSubContentTitleStyle-184">Last name</div> <div class="ProfileContentStyle-179">P</div> </div> <div class="flex1-185"> <div class="ProfileSubContentTitleStyle-184">Preferred first name</div> <div class="ProfileContentStyle-179">P</div> </div> </div> </div> </div> </div>
问题解答
1. 实现逐个朗读姓名分段的效果
当前问题核心是**aria-hidden="true"属性导致整个姓名容器被屏幕阅读器异常处理**,加上无语义的div结构,阅读器无法识别独立分段单元。解决步骤:
- 移除
aria-hidden="true":这个属性会让屏幕阅读器忽略容器内容,导致只能读取合并文本而非逐个分段。 - 使用语义化HTML结构:用
<dl>(定义列表)组织姓名的标签与内容,这是描述键值对的原生语义标签,屏幕阅读器会自动识别每个<dt>(标签)和<dd>(值)的配对关系,实现逐个朗读。
修改后的HTML示例:
<div id="profileNameWrapper"> <div> <div class="ProfileSubHeadTitleLinkStyle-181"> <h3 class="ProfileSubHeadTitleStyle-182">Name</h3> <button type="button" data-testid="edit-link-test-id" class="ms-Link ProfileEditLinkStyle-283"> <i data-icon-name="Edit" aria-hidden="true" class="root-286"></i> Edit </button> </div> <div> <dl class="profileNameColStyle-282"> <div class="flex1-185"> <dt class="ProfileSubContentTitleStyle-184">First name</dt> <dd class="ProfileContentStyle-179">Sarfraj</dd> </div> <div class="flex1-185"> <dt class="ProfileSubContentTitleStyle-184" data-testid="middle-name-test-id">Middle name</dt> <dd class="ProfileContentStyle-179">L</dd> </div> <div class="flex1-185"> <dt class="ProfileSubContentTitleStyle-184">Last name</dt> <dd class="ProfileContentStyle-179">P</dd> </div> <div class="flex1-185"> <dt class="ProfileSubContentTitleStyle-184">Preferred first name</dt> <dd class="ProfileContentStyle-179">P</dd> </div> </dl> </div> </div> </div>
若无法替换为<dl>,也可给每个.flex1-185容器添加role="group"和aria-label(如aria-label="First name section"),帮助阅读器识别分段为独立单元,但语义化标签优先级更高。
2. 浏览模式下焦点行为的官方规则
NVDA和JAWS的浏览模式焦点行为核心遵循WAI-ARIA规范与原生HTML语义,关键规则:
- 原生语义元素优先:带明确语义的HTML标签(如
<h3>、<button>、<dt>、<dd>等)会被识别为独立导航节点,浏览模式下焦点停留在这些元素上,不会直接跳转至子元素。 - 无语义容器的处理:纯
<div>/<span>这类无语义容器,若无ARIA角色(如role="group"、role="region")或属性增强,阅读器会遍历内部语义化子元素,或合并读取容器文本内容,不会将容器本身作为焦点节点。 - 可访问性树影响:浏览模式基于浏览器生成的可访问性树,只有被标记为独立节点的元素才会成为焦点目标。无语义容器默认不会进入可访问性树顶层,因此焦点会直接跳转到内部语义化子元素。
两款阅读器的官方文档均强调,语义化HTML是保证浏览模式行为符合预期的基础,ARIA仅作为语义化标签的补充。
内容的提问来源于stack exchange,提问作者Sarfraj Ansari
相关产品推荐
相关产品推荐

