main 必须是 body 的直接子元素,嵌套会导致 SEO 弱化、无障碍工具报错;header 可多层嵌套但语义不同;table 缺失 thead/tbody/tfoot 会丢失打印、滚动锁定及读屏支持;data-module 比 class 更可靠,因它专为 JS 配置设计,不依赖样式。

为什么不能嵌套在里用
因为 main 是浏览器强制识别的“唯一主体内容容器”,W3C 明确要求每页最多一个,且必须是 body 的直接子元素。把它塞进 div 或 section 里,会导致:
- SEO 信号弱化,搜索引擎可能忽略主体内容权重
- 屏幕阅读器跳过
main,视其为普通块级元素
- axe、WAVE 等无障碍检测工具直接报错
ARIA12
正确写法只有这一种:<body><main>...</main></body>。如果页面有多个逻辑区块(如仪表盘含「订单概览」「用户趋势」「消息通知」),应各自用 section 包裹,main 作为它们的父容器,而不是并列兄弟。
header 和 article 内部的 header 怎么区分
HTML 规范允许 header 出现在任何“章节性内容”内部——包括 body、article、section 甚至 aside。关键不是标签名重复,而是语义层级:
- 页面级
header:只出现一次,放 logo、全局导航,应是 body 的直接子元素
- 文章级
header:每个 article 可独立拥有,用于该文的标题、作者、发布时间等元信息
- CSS 定位时别只靠
header,加类名或用上下文选择器,例如 article header h1 和 body > header h1 分开处理
IE8 不支持 header 标签,但不影响 DOM 结构可用性;若需兼容,引入 html5shiv 即可,无需改结构。
立即学习“前端免费学习笔记(深入)”;
table 的 thead/tbody/tfoot 不写会出什么问题
不写这三层,表格仍能渲染,但会丢失关键语义和功能支撑:
- 打印时
tfoot 无法自动重复在每页底部(如合计行)
- 长表格滚动时,
thead 无法被 CSS position: sticky 锁定(现代浏览器依赖此结构)
- 辅助技术(如读屏软件)无法区分表头与数据,用户需手动遍历确认列含义
- 某些前端表格库(如 DataTables)初始化失败或降级为无序渲染
哪怕只有一个 tr 表头,也建议显式包裹:<thead><tr><th>姓名</th><th>邮箱</th></tr></thead>。不要省略 tbody —— 即使为空,也要写 <tbody></tbody>,否则 DOM 解析时浏览器会自动补全,但补全位置不可控。
data-module 属性比 class="xxx-wrapper" 更可靠的原因
靠 class="product-list-wrapper" 定位模块,本质是把样式层契约挪到 JS 层,极脆弱:
- CSS 文件里删掉这个 class,JS 就找不到节点
- 设计师改稿时重命名 class,没人同步通知前端
- 多个组件共用同一 class 前缀,JS 逻辑互相污染
而 data-module="product-list" 是 HTML 层的“配置契约”:
- JS 用
document.querySelector('[data-module="product-list"]') 获取,完全不依赖样式
- CSS 可用属性选择器:
[data-module="product-list"] { margin-top: 1rem; }
- 支持动态开关:
<div data-module="banner" data-enabled="false">,JS 读取 dataset.enabled 控制行为
注意:data- 属性值必须全小写、不含空格或特殊字符,避免引号逃逸问题;值为空字符串时,dataset 返回 "",不是 undefined。
因为 main 是浏览器强制识别的“唯一主体内容容器”,W3C 明确要求每页最多一个,且必须是 body 的直接子元素。把它塞进 div 或 section 里,会导致:
- SEO 信号弱化,搜索引擎可能忽略主体内容权重
- 屏幕阅读器跳过
main,视其为普通块级元素 - axe、WAVE 等无障碍检测工具直接报错
ARIA12
正确写法只有这一种:<body><main>...</main></body>。如果页面有多个逻辑区块(如仪表盘含「订单概览」「用户趋势」「消息通知」),应各自用 section 包裹,main 作为它们的父容器,而不是并列兄弟。
header 和 article 内部的 header 怎么区分
HTML 规范允许 header 出现在任何“章节性内容”内部——包括 body、article、section 甚至 aside。关键不是标签名重复,而是语义层级:
- 页面级
header:只出现一次,放 logo、全局导航,应是body的直接子元素 - 文章级
header:每个article可独立拥有,用于该文的标题、作者、发布时间等元信息 - CSS 定位时别只靠
header,加类名或用上下文选择器,例如article header h1和body > header h1分开处理
IE8 不支持 header 标签,但不影响 DOM 结构可用性;若需兼容,引入 html5shiv 即可,无需改结构。
立即学习“前端免费学习笔记(深入)”;
table 的 thead/tbody/tfoot 不写会出什么问题
不写这三层,表格仍能渲染,但会丢失关键语义和功能支撑:
- 打印时
tfoot无法自动重复在每页底部(如合计行) - 长表格滚动时,
thead无法被 CSSposition: sticky锁定(现代浏览器依赖此结构) - 辅助技术(如读屏软件)无法区分表头与数据,用户需手动遍历确认列含义
- 某些前端表格库(如 DataTables)初始化失败或降级为无序渲染
哪怕只有一个 tr 表头,也建议显式包裹:<thead><tr><th>姓名</th><th>邮箱</th></tr></thead>。不要省略 tbody —— 即使为空,也要写 <tbody></tbody>,否则 DOM 解析时浏览器会自动补全,但补全位置不可控。
data-module 属性比 class="xxx-wrapper" 更可靠的原因
靠 class="product-list-wrapper" 定位模块,本质是把样式层契约挪到 JS 层,极脆弱:
- CSS 文件里删掉这个 class,JS 就找不到节点
- 设计师改稿时重命名 class,没人同步通知前端
- 多个组件共用同一 class 前缀,JS 逻辑互相污染
而 data-module="product-list" 是 HTML 层的“配置契约”:
- JS 用
document.querySelector('[data-module="product-list"]')获取,完全不依赖样式 - CSS 可用属性选择器:
[data-module="product-list"] { margin-top: 1rem; } - 支持动态开关:
<div data-module="banner" data-enabled="false">,JS 读取dataset.enabled控制行为
注意:data- 属性值必须全小写、不含空格或特殊字符,避免引号逃逸问题;值为空字符串时,dataset 返回 "",不是 undefined。



















