语义化标签是DOM结构稳定性的核心锚点,强制约束层级、隐含ARIA角色与outline行为;替换为div会导致CSS/JS失效、屏幕阅读器导航断裂;必须确保<main>唯一且不嵌套,标题严格递进,DOCTYPE和lang属性不可缺失。

语义化标签直接决定 DOM 树是否可预测
浏览器解析 HTML 时,<header>、<main>、<article> 这类语义标签不是“视觉装饰”,而是强制约束 DOM 层级走向的锚点。它们自带隐式 ARIA 角色和默认 outline 行为,一旦被替换为 <div>,DOM 就失去结构契约——CSS 选择器可能失效,JS document.querySelector('main') 返回 null,屏幕阅读器导航树断裂。
常见错误现象:querySelector('main') 在开发环境返回元素,上线后突然为 null;或 Lighthouse 报错 “main element is missing” 却找不到明显缺失位置——往往是因为某处用 <div class="main"> 冒充了 <main>,而构建工具(如 Webpack + html-webpack-plugin)又自动注入了额外 wrapper。
- 必须确保
<main>在整个文档中只出现一次,且不嵌套在<article>或<section>内部 -
<nav>只包裹主导航链接,面包屑、页内锚点、版权信息链接都不属于它 - 动态插入内容时,避免用
innerHTML覆盖整个<main>,应使用replaceChildren()或textContent+ 结构重建,防止意外抹除语义边界
标题层级错乱会瓦解整个内容骨架
<h1> 到 <h6> 不是字号调节开关,而是 DOM 中不可跳过的逻辑链。搜索引擎和 VoiceOver 都依赖这个序列建立内容索引与导航路径。跳级(如 <h2> 后直接 <h4>)、重复使用 <h1>、或把标题塞进 <div> 再用 CSS 模拟样式,都会让结构“脱钩”。
使用场景:单页应用中路由切换时,若未重置 document.title 且未同步更新页面内 <h1>,会导致 SEO 抓取到旧标题,辅助技术用户听到的仍是上一页的主标题。
立即学习“前端免费学习笔记(深入)”;
- 每个
<article>或<section>应以<h2>或更高级别标题起始,内部子级严格递进 - 禁止用
font-size和font-weight模拟标题,必须用真实标题标签 - 服务端渲染(SSR)时,
<h1>必须由后端注入,不能靠 JS 在客户端补 —— 否则首屏 HTML 中无<h1>,Lighthouse 直接扣分
嵌套深度超 6 层会触发 DOM 解析退化
DOM 深度不是“看起来多深”,而是从 <html> 到最内层元素的实际节点数。Chrome DevTools 的 Elements 面板右键 → “Show DOM properties” 显示的 depth 值超过 6,就会显著拖慢 touchstart 响应、增加首次内容绘制(FCP)耗时,尤其在低端 Android 设备上。
性能影响:实测 <body><div><div><div><div><div><button>(深度 7)比 <main><nav><button>(深度 3)平均多出 30ms 事件冒泡延迟,且 CSS 选择器匹配速度下降约 40%。
- 用
display: contents替代无意义的<div>包裹层(注意 Safari 15.4+ 才支持) - 避免在
<table>单元格里再套<div>+<span>堆叠样式 - 动态生成菜单时,用
DocumentFragment批量插入,而不是循环appendChild—— 每次调用都可能触发 layout,加深实际渲染深度
DOCTYPE 和 lang 属性缺失会让结构“失语”
<!DOCTYPE html> 不只是个声明,它是浏览器开启标准模式的钥匙。缺它,IE 和部分 WebView 会降级到混杂模式(Quirks Mode),导致 <main>、<section> 等语义标签被忽略,CSS box-sizing 行为异常,甚至 JS getBoundingClientRect() 返回错误坐标。
lang 属性则决定屏幕阅读器发音规则和搜索引擎语言判定。没有它,中文页面可能被识别为英文,VoiceOver 用英语朗读汉字,拼音全错。
-
<html lang="zh-CN">必须存在,且值要精确(如港澳台用zh-HK、zh-TW) - 不要写成
<html lang="zh">—— 太宽泛,部分辅助技术无法适配方言发音 - 服务端模板中,
lang值应随用户语言偏好动态输出,而非硬编码



















