lang属性必须写在对应html元素上且符合bcp 47标准,否则屏幕阅读器误读;仅提供语义锚点,需配合aria-label或speechsynthesis实现语音强调;控件须有可访问名称;web speech api需满足语音就绪、显式设lang、用户手势触发三条件。

lang 属性必须写在对应 HTML 元素上,且值要符合 BCP 47 标准
不设 lang,屏幕阅读器大概率按系统默认语言读,中文常被当成英文切音节,比如“行”读成 “háng” 而非 “xíng”。lang 不是可选装饰,而是语音引擎识别语言的唯一依据。
常见错误包括:lang="zh"(缺地区码)、lang="chinese"(非标准)、或只写在 标签却忽略局部语言切换。
-
设全局默认,但英文引文得单独加:<p lang="en-US">The quick brown fox</p> - 嵌套内容如
<div lang="en">...<span>世界</span> </div>中的 “世界” 仍按英文读——必须给<span lang="zh-CN">世界</span> - 动态更新语言时,不能只改 innerHTML,还得同步设
document.documentElement.lang或对应元素的lang属性
用 <mark></mark> 标注上下文重点,但别指望它自动触发语音提示
<mark></mark> 是 HTML5 唯一语义化标注“上下文相关重点”的标签,比如搜索结果中的关键词、教程里的核心术语。但它本身不会让屏幕阅读器多读一句“注意”,也不会自动高亮语音——视觉样式和辅助技术必须配合。
- 必须保留背景色(如
mark { background-color: #ffeb3b; }),否则低视力用户无法识别重点 - 想让语音助手强调它,得加
aria-label,例如:<mark aria-label="重点词汇:响应式布局">响应式布局</mark> - 别套
role="note"或role="complementary"——会覆盖<mark></mark>的原语义,部分读屏软件直接跳过 - 若需点击后朗读该重点内容,必须用 JavaScript +
SpeechSynthesis,<mark></mark>只负责语义锚点
按钮、表单、图片等控件必须靠 ARIA 或原生语义补全可访问名称
语音助手靠可访问树理解页面意图。一个没文本的 <button></button>,读出来就是“按钮”,用户不知道点它干啥;一张没 alt 的图,可能读文件名或静默跳过。
-
aria-label用于无可见文本的控件,如图标按钮:<button aria-label="关闭"></button> -
aria-labelledby用于组合多个元素文本,如图表标题+说明,但绝不能和aria-label同时出现 - 纯装饰图必须写
alt="",不是留空或写alt="图片"——前者明确指令跳过,后者反而打断上下文 - 表单输入框没
<label></label>关联,语音助手只会读“编辑文本”,务必用for/id配对或aria-labelledby
Web Speech API 的调用必须满足三个硬性条件,否则必静音
HTML 本身不发声,SpeechSynthesis 是唯一原生方案,但它受浏览器策略强约束。90% 的“没声音”问题都出在这三件事没做对:
- 语音列表异步加载:首次
speechSynthesis.getVoices()返回空数组,必须监听speechSynthesis.onvoiceschanged或轮询,不能在DOMContentLoaded里直接调用speak() - 语言必须显式指定:
utterance.lang = 'zh-CN',不写或写错(如'zh')会导致 fallback 到英文语音,吐字含糊 - 必须由用户手势同步触发:iOS Safari、微信 X5 内核等环境,
speechSynthesis.speak()只能在click或touchstart回调里**直接调用**,放进setTimeout、Promise.then或 fetch 回调就失效
真正难的不是写几行 JS,而是让每个环节都稳——语音就绪时机、语言匹配精度、用户交互链路,漏掉任意一环,跨平台就只剩“看起来能用”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











