html文档必须以开头并声明lang属性,和须存在且不重复,语义标签如不可替代,表单控件必须用显式关联,原生语义元素优于role模拟。

HTML 文档必须以 开头并声明 <code>lang
没有 ,浏览器会进入怪异模式,ARIA 属性和语义标签行为不可靠;<code>lang 缺失会导致屏幕阅读器(如 NVDA、VoiceOver)按系统默认语言朗读,中文页面可能被读成英文或日文。常见错误是只写 ,漏掉 DOCTYPE 或 lang。lang 值推荐用 zh-CN(简体中文),而非 zh(不明确区域)或空值;港澳台场景可选 zh-HK、zh-TW,但不要混用。
<title></title> 和 <h1></h1> 必须存在且内容不重复
<title></title> 是浏览器标签页和读屏软件识别页面的首要依据,每个页面必须唯一;静态模板里写死 <title>我的网站</title> 会导致所有页面标题雷同,AT 用户无法区分。动态页面需用 JS 同步更新:document.title = '用户中心'。同理,<h1></h1> 应为当前页核心主题,不能全站统一写“欢迎来到首页”。注意:JS 修改 <h1></h1> 文本(如 document.querySelector('h1').textContent = '订单详情')后,读屏会立即重读,但若仅靠 CSS 隐藏再显示,不会触发朗读。
用 <header></header>、<nav></nav>、<main></main>、<footer></footer> 替代 <div class="header">
<p>语义标签不是“锦上添花”,而是读屏软件跳转区域的依据:<code><nav></nav> 支持快捷键(NVDA + Insert + N)直接进入导航区;<main></main> 只能出现一次,且必须包裹主体内容,否则 AT 会忽略后续结构。常见错误包括:<nav></nav> 里只放版权信息(应放主导航链接),或把多个 <section></section> 嵌套在 <main></main> 外;<main></main> 被 display: none 隐藏时,仍会被读出——该用 aria-hidden="true" 或彻底移除 DOM。
表单控件没 <label></label> 就等于没写
<label></label> 就等于没写读屏软件不会自动关联视觉上靠近的文本和 <input>。必须显式绑定:<label for="email">邮箱</label><input id="email" type="email">,或嵌套:<label>邮箱<input type="email"></label>。嵌套写法禁用块级元素(如 <div> 包裹 <code><input>),否则部分读屏中断朗读。placeholder 不是 <label></label> 替代品——它在输入后消失,且不被所有读屏支持;aria-label 仅用于无可见文本的控件(如纯图标按钮),表单字段优先用真实 <label></label>。
复杂点在于:语义结构一旦写错,修复成本远高于初期规范。比如用 <div role="button"> 代替 <code><button></button>,后续要补 tabindex、键盘事件监听、焦点管理、状态同步——而一个原生 <button></button> 自带全部。真正容易被忽略的,是那些“看起来正常”的地方:DOM 顺序与视觉顺序不一致、<main></main> 缺失、lang 值写错,这些都不会报错,但会让 AT 用户迷失。











