main必须唯一且直接为body子元素,否则触发无障碍与seo双重崩溃;data-module与data-version需组合使用形成可追溯dom契约;语义标签是浏览器、爬虫与辅助技术共同依赖的硬接口,须同步更新js查询逻辑。

main必须且只能出现一次,否则 axe、Lighthouse 会直接报错;data-module和data-version是 JS 查询稳定性的唯一锚点;语义标签不是“可选装饰”,而是浏览器、屏幕阅读器、爬虫和新同事共同依赖的接口契约。
为什么重复或缺失会立刻崩掉无障碍与SEO
多个main会让屏幕阅读器无法判断“哪块才是用户该聚焦的主体内容”,触发 W3C ARIA 规范 violation;完全缺失则导致搜索引擎抓取时权重分散,Lighthouse 的“Accessibility”分项直接扣 20+ 分。
-
main必须直接包裹至少一个h1–h6,否则部分爬虫判定为“空内容页”,跳过索引 - SPA 场景下,
main应套在动态渲染区(如#app内部),而非静态壳层——否则路由切换后main内无内容,辅助技术失焦 - 服务端模板中若用条件注释移除
main,必须提供带语义的 fallback(如section[aria-labelledby="fallback-title"])
data-module 和 data-version 怎么用才不白写
只加data-module="header"没用,必须配合data-version="2.1"才能形成可追溯契约。CI 流程可校验该值是否匹配设计文档中的接口定义,避免前端改了结构但下游组件仍按旧版解析。
- JS 查询必须写成
document.querySelectorAll('[data-module="product-card"][data-version="2.0"]'),不能只靠data-module——版本升级时旧逻辑可并行保留 -
data-module值要全局唯一且带业务语义:product-card比card安全,checkout-step-2比step2明确 - 禁止在
data-module里塞动态值(如data-module="header-{{env}}"),它不是模板变量,而是 DOM 层硬接口
语义标签不是“换汤不换药”,而是替换 class 绑定的前提
把<div class="nav">改成<code><nav></nav>本身不提升可维护性;只有同步删掉所有document.querySelector('.nav'),换成document.querySelector('nav'),才算真正解耦。
-
nav只包链接,logo、搜索框、用户头像必须归入header——否则 Tab 键导航会跳过非链接元素,Lighthouse 报“navigation not keyboard accessible” -
aside不是“右边栏”,必须与当前上下文强相关(如文章末的作者简介);纯广告位用div data-module="ad-banner"更准确 - 连续两个主题一致的
section(如“产品介绍”+“参数表”)应合并,用h2/h3分层,否则语义流断裂,辅助技术无法建立内容关联
嵌套超过三层就该重构,而不是加注释
审查元素里点四下才能定位到p文本,说明结构已失控。这不是“多几层 div 无所谓”,而是 CSS 选择器变脆弱、JS 查询变慢、无障碍焦点路径变长的综合信号。
- 检查方式:Chrome DevTools → Elements → 右键节点 → “Break on” → “Attribute modifications”,能快速暴露冗余包裹层
- 合并策略:相邻的
div若都只起容器作用且无样式/交互差异,优先用display: contents或直接删掉一层 - 构建阶段可加 ESLint 插件(如
eslint-plugin-html)校验嵌套深度,>3 层自动告警
最易被忽略的点:语义标签和data-属性必须同步落地——写了main却还在 JS 里用document.getElementById('main-content'),等于白做;加了data-module却不更新查询逻辑,版本号就只是个字符串。











