JS无法真正模拟语义结构,因屏幕阅读器依赖原生HTML标签识别页面骨架;导航、主内容等必须在初始HTML中存在,不可JS动态插入;按钮、表单、图片、标题等须用原生语义化标签,避免用div+role或JS补救。

为什么不能用 JS 模拟语义结构
JS 生成的按钮、导航或标题,对屏幕阅读器来说只是普通文本或无意义容器——它读不出“这是菜单”“这是主内容”,键盘焦点也进不去。哪怕加了 role="button" 和 tabindex="0",也只算“勉强可用”,不是真正语义化。
常见错误现象:
- 点击
<div onclick="...">后屏幕阅读器不播报动作反馈 - 用 JS 动态插入的
<nav>被忽略,M 键跳转不到 - JS 渲染的标题层级断裂(比如从
<h3>直接跳到<h1>),导致大纲混乱
<nav> 和 <main> 必须原生写在 HTML 中
它们是辅助技术识别页面骨架的锚点,必须在初始 HTML 里就存在,不能靠 JS 插入或替换。
正确做法:
立即学习“前端免费学习笔记(深入)”;
- 服务端渲染或静态 HTML 中直接写出
<nav aria-label="主导航">,而非等 JS 加载后再document.createElement('nav') -
<main>全局唯一,且只包裹用户真正要读/操作的内容(如文章正文、表单主体),不包 header、侧边栏、广告位 - Next.js 或 React SSR 场景下,确保布局组件中只有一个
<main>,子页面不要重复渲染
表单和图片的语义替代 JS 补救
缺失语义带来的问题,后期用 JS 修复成本高、风险大——比如监听 focus 手动播报提示,或动态注入 ARIA 属性,这些逻辑易漏、难测、拖慢响应。
直接用原生语义替代:
- 按钮不用
<div onclick="submit()">,改用<button type="button">或<input type="submit"> - 表单控件必须显式绑定:
<label for="email">邮箱</label><input id="email" type="email">,或嵌套写法:<label>邮箱<input type="email"></label> - 图片必须带
alt:装饰图用alt="",内容图用描述性文字,禁止留空或填文件名(如icon_menu.png)
标题层级不能靠 JS 重排
WCAG 要求标题按逻辑顺序嵌套(<h1> → <h2> → <h3>),屏幕阅读器靠此生成文档大纲。JS 动态修改 innerHTML 或切换 class 改变视觉大小,但不改标签本身,毫无意义。
容易踩的坑:
- 页面从
<h2>开始,但<main>外堆了三个<h1>,导致大纲断裂 - 用 CSS 把
<p class="title">样式成大号字,却没改标签,读屏仍当段落处理 - React 组件中多个
<h3>并列出现,但父级没<h2>,破坏层级
标题结构一旦错,后续所有 ARIA 补救都难覆盖——它不是样式问题,是文档骨架问题。



















