HTML语义标签需严格遵循内容模型:p内禁用div/ul/标题,header/footer不可嵌套nav/main等容器,ul/ol必须直接包含li,main不得嵌套于其他语义元素内。

不要在 <p> 里塞 <div>、<ul> 或标题标签
<p> 只允许行内容(phrasing content),比如文本、<strong>、<img>。一旦写成 <p><div>文字</div></p>,浏览器会立刻中断 <p>,把 <div> 移到外面——DOM 结构就和你写的完全不一致了。
常见后果包括:
- CSS 中
p > div选择器完全不生效 -
document.querySelector('p').children返回空 NodeList - JS 动态插入内容时位置错乱
想包多块内容?用 <section> 或 <article>;想加列表或标题?先关掉 <p>,再平级放 <h2> 和 <ul>。
<header> 和 <footer> 里禁止嵌套 <nav>、<main> 或另一个语义容器
<header> 不是“页面顶部大横条”,而是某个区块的页眉,只该放与当前上下文直接相关的元信息:比如 <h1>、logo、简短说明性 <p>。同理,<footer> 只承载版权、联系方式、相关链接这类尾部信息。
立即学习“前端免费学习笔记(深入)”;
典型错误写法:
<header> <nav><ul><li>首页</li></ul></nav> </header>
这会让辅助技术误判结构,也违反 W3C 内容模型。正确做法是把 <nav> 提一级,和 <header> 并列;若需视觉组合,用 <section> 包裹二者,各自保持语义纯净。
<ul> 和 <ol> 必须直接包裹 <li>,不能插 <div> 或 <p>
<ul> 的内容模型明确要求子元素只能是 <li>(零个或多个)。写成这样:
<ul class="menu"> <div class="item">首页</div> <div class="item">关于</div> </ul>
浏览器会自动拆解:先闭合 <ul>,再把两个 <div> 当作独立节点插入 body。结果是 DOM 断裂、ul li:last-child 失效、屏幕阅读器无法识别为列表。
修复方式只有两种:
- 把
<div class="item">换成<li class="item"> - 如果真需要额外容器(比如做动画组),用
<li><div class="item">...</div></li>,确保<li>是<ul>的直接子元素
<main> 不能嵌套在 <article>、<aside>、<footer>、<header> 或 <nav> 内部
<main> 表示整个文档的唯一主体内容,W3C 明确规定它不能出现在其他语义容器内部。写成 <article><main>.../article> 会导致语义冲突:既说这是“独立可分发的内容单元”,又说它是“整页唯一主内容”——逻辑矛盾。
实际开发中容易踩坑的场景:
- 博客文章页:用
<article>包裹单篇文章,但<main>应包裹整页主体(含文章 + 评论区 + 相关推荐等),而非只包<article> - 仪表盘页面:侧边栏用
<aside>,顶部用<header>,<main>必须是它们的兄弟节点,不能被任何语义标签包裹
最稳妥的检查方式:打开浏览器 Elements 面板,确认 <main> 是 <body> 的直接子元素,且全页只出现一次。



















