语义标签代替div堆叠是必须的:header、nav、main等自带隐含语义和aria role,须严格遵循层级约束(如main不可嵌套article)、内容相关性(aside须关联邻近article)及布局绑定(grid-template-areas),并避免冗余dom嵌套。

用语义标签代替 div 堆叠,不是可选,是必须
很多人写 <div class="header"> 时觉得“反正样式能对上就行”,但这就放弃了浏览器和屏幕阅读器自动识别结构的能力。header、nav、main、section、article、aside、footer 不是装饰,它们自带隐含语义和默认 ARIA role。
<ul>
<li>
<code><main></main> 必须且只能出现一次,不能嵌套在 <article></article> 或 <section></section> 里;否则开发者工具会标红,辅助技术会误读内容层级
<nav></nav> 只该放链接,混入 <button></button> 或用户状态文本(如“你好,张三”)会破坏导航语义,应移至 <header></header> 或独立 <section></section>
<aside></aside> 内容必须与邻近的 <article></article> 或 <section></section> 相关;全站广告位别硬塞这儿,改用 <section role="complementary"></section> 更准确<header></header> 是允许的(比如每篇 <article></article> 都有自己的),但不要用一个顶层 <header></header> 包住所有标题——这会让内容粒度丢失,SEO 和无障碍都受损模块复用该选构建时内联,而不是运行时 fetch
想复用 header.html 和 footer.html?别用 fetch() + insertAdjacentHTML(),它不触发代码拆分、无模块语义、XSS 风险高,且热更新不生效。
- 推荐方案:用
rollup-plugin-html或posthtml-include,在打包阶段把片段静态注入主 HTML;输出仍是单个文件,零运行时开销 - 语法示例:
<include src="header.html"></include>,路径基准是入口 HTML 所在目录,不是当前文件位置 - 注意:这些插件不支持动态传参(比如
<include src="card.html" title="Hello"></include>),真需要变量渲染,得上模板引擎(如 EJS、Nunjucks) - 如果必须运行时加载(如 SPA 中局部刷新),务必用
insertAdjacentHTML('beforeend', html)替代innerHTML = html,并加 fallback 和缓存控制(fetch(url, { cache: 'force-cache' }))
布局绑定语义结构,别靠 div + class 拼样式
光有语义标签不够,得让它们在视觉上真正“分得开”。浮动、绝对定位早该淘汰,现代布局必须绑定语义容器。
- 用
display: grid+grid-template-areas显式声明区域:"header header" "nav main" "footer footer",再给每个语义标签设grid-area: header等 - Flex 布局也行,但要确保
<main></main>是直接子元素,别被多余<div class="container"> 包裹——那层 div 没语义,纯属冗余 <li>DOM 嵌套别超三层:实测 <code><div><div><div> <p> 这种结构会让 CSS 选择器匹配变慢,滚动卡顿;用 Grid/Flex 一步替代 2–3 层包裹容器 </p> <li>动态列表插入大量项时,用 <code>DocumentFragment批量操作,避免逐条appendChild触发多次重排 -
<main></main>不能作为<article></article>的子元素——<article></article>是独立内容单元,<main></main>是页面级容器,二者层级冲突 -
<footer></footer>不该出现在<header></header>内部,哪怕视觉上它紧贴顶部下方;页脚语义上是兄弟关系,不是子内容 -
<nav></nav>里塞搜索框或登录表单,会破坏导航语义;这类交互组件应抽离到<header></header>或单独<section></section> - 检查方式:用 Chrome 开发者工具 Elements 面板,右键节点 → “Inspect Accessibility”,看 role 和 name 是否符合预期
模块边界失效常因嵌套违反隐含逻辑
语义标签之间有隐含层级约束,错配会导致结构混乱、无障碍失效,甚至被 Lighthouse 标为严重错误。











