不加lang、嵌套<main>、跳级用标题、靠class查DOM——这四类写法,哪怕视觉完全正常,也已在渲染安全、无障碍、可维护性三方面同时失守。

直接说结论:不加 lang、嵌套 <main></main>、跳级用标题、靠 class 查 DOM —— 这四类写法,哪怕视觉完全正常,也已在渲染安全、无障碍、可维护性三方面同时失守。
为什么 lang="zh-CN" 不是可选项而是强制起点
浏览器和屏幕阅读器(NVDA、VoiceOver)依赖 lang 属性决定语音引擎、分词逻辑、标点朗读方式。写成 lang="ch" 或漏掉,中文内容大概率被读成日文语调,或直接跳过整段;lang="zh" 不符合 IETF 标准,部分 AT 工具会 fallback 到默认语言(通常是英文)。
-
lang必须写在标签上,不能只在<meta>里补,也不能靠 JS 动态插入——SSR 或初始 HTML 就得对 - 局部语言切换要用嵌套,比如英文引文:
<p lang="en">Hello world</p> - 多语言站点中,
lang值必须与实际内容严格匹配,否则 axe、WAVE 等工具会报「Language not declared」严重错误
<main></main> 只能有一个且必须是 的直接子元素
这是 W3C 明确规定的结构约束。<main></main> 被设计为页面唯一主内容区,它的语义是“独立、可分发、可索引”。一旦嵌套在 <div>、<code><section></section> 或另一个 <main></main> 里,屏幕阅读器会忽略它,Googlebot 也可能降权处理。
- 常见错误:
<body><div class="wrapper"><main>...</main></div></body>—— 这个<main></main>在无障碍树里根本不可见 - 正确写法:
<body><header>...</header><main>...</main><footer>...</footer></body> -
<main></main>内部可以有自己的<header></header>和<footer></footer>,但不能再出现第二个<main></main>
标题层级断裂会让屏幕阅读器“掉层”,不是提示问题而是逻辑塌方
用户按 H 键逐级跳转时,依赖的是显式存在的 <h1>~<h6> 标签构成的语义树。如果页面结构是 <h2>产品介绍</h2><h4>规格参数</h4>,中间缺了 <h3>,AT 就会认为“产品介绍”章节已结束,后续内容无法被定位。
立即学习“前端免费学习笔记(深入)”;
- 常见诱因:CSS 隐藏了某个标题但没删 DOM;组件库默认用
<h2>作卡片标题,而卡片本身又在<h2>主区域下 - 修复原则:要么补上缺失层级,要么调整结构——比如把卡片标题降级为
<h3>,或用<div role="heading" aria-level="3">替代(仅当无法改标签时) - 每个
<section>应以一个<h2>或更高级别标题开头;纯视觉分隔不用<section>
用 data-module 替代 class 做 JS 查询锚点
靠 class="header" 或 class="nav-active" 来选 DOM,本质是把样式逻辑和行为逻辑耦合在一起。设计师改个主题、前端换套 UI 库,class 名可能还在,但语义早已失效;多人协作时,class="header-v2-fix" 和 class="header-new" 并存是常态,没人敢删。
- 模块根元素统一加
data-module="header"、data-module="product-list",JS 查找用document.querySelectorAll('[data-module="header"]') - 配合
data-version="1.3",CI 流程可自动校验 HTML 片段是否匹配文档版本 - 禁用
id做模块标识——循环渲染时必然重复,document.getElementById()只返回第一个
真正难的不是记住这些规则,而是当一个老项目里 <main></main> 嵌在五层 <div> 里、<code>lang 写成 "zh"、标题从 h2 直接跳到 h5 时,你敢不敢动、怎么动、动完怎么验证。这些不是“最佳实践”,是底线——踩破了,安全、无障碍、可维护性就全在线下运行。



















