必须显式写结束标签的标签包括<p>、<div>、<section>、<header>、<script>、<style>、<textarea>、<select>等非void元素;仅HTML Living Standard定义的14个void元素(如<img>、<input>、)语法上禁止结束标签。

最直接的办法是:所有非空元素都显式写闭合标签,自闭合元素不加斜杠,不省略任何结束符。
哪些标签必须写结束标签
像 <p>、<div>、<section>、<header>、<script>、<style>、<textarea>、<select> 这类标签,HTML 规范要求必须成对出现。哪怕内容为空,也要写 <script></script> 或 <div></div>。
常见错误包括:
-
<script src="app.js" />—— 浏览器会忽略斜杠,但构建工具可能误判,JS 不执行 -
<textarea></textarea>写成<textarea />—— 直接丢失所有用户输入或默认文本 -
<p>Hello<div>World</div>—— <p> 遇到 <div> 会立刻被自动闭合,后续结构全乱
哪些标签可以不写结束标签(但不建议省略)
HTML5 允许少数标签在特定上下文中省略结束标签,比如 <p>、<li>、<dt>、<dd>。但这只是解析器“猜出来”的结果,并非推荐写法。
立即学习“前端免费学习笔记(深入)”;
省略的风险很实际:
- 动态插入内容(如模板渲染、富文本粘贴)会破坏上下文,自动闭合失效
- Git diff 难以追踪,代码审查时容易漏掉嵌套问题
- W3C 校验器报错,CI/CD 流水线可能拦截提交
- JS 操作
parent.children时拿到的节点顺序和预期不符
自闭合标签怎么写才安全
只有 HTML Living Standard 明确定义的 14 个 void elements(如 <img>、<input>、<meta>、<link>、<br>)才真正支持自闭合。它们语法上禁止写结束标签。
正确写法统一用:<img src="a.jpg" alt="描述">,不加 />。
加斜杠的问题不在浏览器端(它会忽略),而在工具链:
- Vue 单文件组件中,
<img />可能被当作 XML 解析,导致属性截断 - Jekyll、Hugo 等静态生成器的部分插件按 XML 规则处理,
/>会被当成标签终止信号 - Emmet 插件输出
<img />是历史遗留行为,建议关闭或重配为无斜杠格式
实时拼接 HTML 时怎么避免自动修复
别用 element.innerHTML += 拼接未完成的标签,比如先写 <p>开始,再追加 结束</p>。浏览器每次设置 innerHTML 都会丢弃旧 DOM、重新完整解析字符串,遇到孤立 <p> 就自动补成 <p>开始</p>,后半段变成纯文本。
可靠做法是:
- 用 JavaScript 变量缓存完整 HTML 字符串
- 每次更新时,拼好整个字符串再一次性赋值:
el.innerHTML = fullHtml - 服务端流式渲染或协作编辑器等场景,必须走这个路径,不能依赖“浏览器会帮我修好”
怎么快速发现闭合问题
别只看源码,重点检查真实 DOM:
- 打开 Chrome DevTools → Elements 面板,看有没有红色高亮、灰色提示或结构跳变
- 右键某节点 → “Edit as HTML”,改一个字符,如果整块结构重排,说明已被浏览器修复过
- 把 HTML 粘进 W3C Markup Validator,它会明确标出 “Start tag not closed” 或 “End tag for element X omitted”
- 特别盯 <table>、<ul>、<ol> 内部——塞了 <div> 或 <p> 就会触发静默移出,列表/表格语义直接崩塌



















