可访问性问题多因细节错误而非缺失:lang属性须用iana标准值且置于html根元素;main必须为body直接子元素;label须显式绑定表单控件;iframe必须设具体title;组合语义需整体合规。

绝大多数可访问性问题不是因为“没做”,而是因为“做了但没做对”——尤其是那些看起来无关紧要、浏览器也不报错的细节。
lang 属性写错或漏写,中文页面可能被读成日语
lang="zh" 或 lang="cn" 看似合理,但 NVDA、VoiceOver 会当作无效值处理,转而按系统默认语言朗读,常见后果是中文分词错误、声调全乱、甚至整段读成日语。必须用 IANA 注册的标准值:lang="zh-CN"(简体)或 lang="zh-TW"(繁体)。
-
必须顶格出现在文档最开头,前面不能有 BOM、空格或注释 - 多语言内容需嵌套声明,比如英文引文:
<p lang="en">The quick brown fox</p> - React/Vue 中避免 JS 动态拼接 lang 值;SSR 渲染出的首屏 HTML 必须带对,否则初始朗读已错
嵌套在 div 里,整个主内容区会被屏幕阅读器跳过
<main></main> 不是样式容器,它是辅助技术识别“页面核心内容”的唯一信标。主流 AT(如 NVDA)只认 <main></main> 这个直系路径。一旦包在 <div class="wrapper"> 里,<code><main></main> 就失效了。
-
<main></main>必须是的直接子元素,且全局唯一 - 不能嵌套另一个
<main></main>,哪怕组件复用也不行 - 若需外层布局容器,改用
<div role="region" aria-label="主内容">,不破坏语义流 <li>axe-core 等工具会直接报 <code>document-has-main严重错误 - 推荐包裹写法:
<label>邮箱<input type="email"></label>,简单、兼容性好、点击文字即聚焦 - 无法加 id 时慎用
for/id绑定;<label for="email">邮箱</label><input id="email" type="email">要求 id 唯一且稳定 - 绝对不要:
<div>邮箱<input type="email"> </div>—— 对可访问性零贡献 - 图标按钮(如搜索放大镜)也要 label:
<label><svg></svg>搜索</label><input type="search"> -
title值必须具体:title="嵌入式客服聊天窗口",不能是title="内容"或空字符串 - 第三方嵌入代码(如地图 SDK、客服 widget)常默认无 title,务必手动补全
- 若 iframe 内容动态变化(如切换不同客服坐席),需用 JavaScript 同步更新
title属性 -
sandbox和loading="lazy"再重要,也不能替代title—— 安全与性能不能牺牲可访问性底线
label 没显式绑定,表单字段对键盘和屏幕阅读器完全“失联”
仅靠视觉对齐(比如 CSS 把文字挨着 input 放)毫无意义。屏幕阅读器聚焦到 <input type="email"> 时,若无 <label></label> 关联,用户根本不知道这是邮箱、密码还是验证码。
iframe 缺少 title,嵌入内容等于“黑盒”
未设 title 的 <iframe></iframe> 在 VoiceOver/NVDA 中只会报“框架”或“无标题框架”,用户无法预判内容类型,极易跳过关键区域(如客服弹窗、地图、登录表单)。
最容易被忽略的,其实是组合动作:比如用了 <nav></nav> 却没确保其中每个链接都有真实导航意图;写了 <h2></h2> 却没检查父级是否已是 <h1></h1>;加了 alt 却填了文件名而非信息功能。这些点单独看都小,合起来就是用户卡在页面里出不去的根本原因。











