原生html元素本身就能提供系统级可访问性,前提是正确使用语义化标签、不绕开语义、不依赖aria“打补丁”掩盖结构缺陷;屏幕阅读器优先信任原生语义,如自带焦点与交互,天然建立导航上下文,确保表单分组可靠,标题必须用-维持逻辑层级,表单控件须为原生元素并正确绑定label,lang和charset是语音合成与字符解析的系统前提。

原生HTML元素本身就能提供系统级可访问性——前提是用对标签、不绕开语义、不靠ARIA“打补丁”去掩盖结构缺陷。
用对语义标签比加ARIA更有效
屏幕阅读器和辅助技术优先信任原生语义,而不是你手动塞的role或aria-label。比如:
-
<button></button>自带焦点、空格/Enter触发、disabled状态、表单集成,而<div role="button">什么都没有,得自己补全所有行为 <li> <code><nav></nav>被读屏软件识别为导航区,<div role="navigation">只是“看起来像”,但缺失语义继承链(比如嵌套<code><ul><li><a></a></li></ul>时,<nav></nav>会自动建立上下文) -
<fieldset></fieldset>+<legend></legend>天然形成逻辑分组,比<div aria-labelledby="xxx">更可靠:前者在表单重置、键盘导航、读屏上下文中都被一致支持 <h3>表单控件必须用原生input/select/textarea</h3> <p>自定义封装(如<code>x-toggle)可以存在,但核心交互节点必须是原生表单控件:- 任何参与表单提交、重置、验证的开关/输入,内部必须挂载真实
<input type="checkbox">或<input type="text"> - 不能只靠
shadowRoot.querySelector('input').checked = true就认为它接入了表单——必须声明static formAssociated = true,且构造函数第一行调用super() -
label必须用for属性或包裹方式绑定到原生控件,否则clicklabel 不会触发 focus + toggle,屏幕阅读器也无法建立关联
标题层级与文档流不能跳级或断裂
可访问性导航严重依赖
<h1></h1>–<h6></h6>的逻辑嵌套,不是视觉样式问题:-
<h2></h2>后面直接跟<h4></h4>会导致读屏软件跳过中间层级,用户丢失内容结构感知 - 用
font-size模拟标题但不用<h3></h3>,等于把内容降级为普通段落——<p class="h3"></p>在AT眼里就是<p></p> - 动态渲染内容(如SPA路由切换)必须同步更新
<h1></h1>,不能只靠JS改文本却不触发document.title或aria-live通知
lang属性和字符编码是系统级前提
这两个看似基础的设置,直接影响语音合成引擎能否正确发音、能否解析字符:
-
必须存在且准确——lang="zh"或lang="cn"都不合法,会导致部分读屏软件回退到默认语言发音 -
<meta charset="UTF-8">必须在最前面,否则中文、emoji等可能乱码,辅助技术直接报错或静音跳过 - 页面内多语言片段需局部标注,如
<span lang="en">API</span>,否则混用中英文时语音引擎会卡顿或错误切音
真正难的不是写
role="tablist",而是克制住不用div替代button、不用span替代strong、不用JS模拟原生行为——系统级可访问性,始于对原生语义的敬畏,而非对ARIA的依赖。 - 任何参与表单提交、重置、验证的开关/输入,内部必须挂载真实











