是强制根节点,必须且只能有一个;缺失时浏览器降级为纯文本渲染,dom构建失败,导致样式、脚本、meta全部失效,document.body和document.head返回null,seo与hydration均受损。

不是装饰,是强制根节点;没它,浏览器就当纯文本渲染——哪怕只写 <p>Hello</p> 也无效。
为什么 必须存在且只能有一个
HTML 解析器启动时第一件事就是找 开始构建文档对象模型(DOM)。没有它,所有子标签(包括 和 )都会被降级为“孤儿节点”,样式、脚本、meta 行为全部失效。
常见错误现象:
- 页面完全无样式,
<link rel="stylesheet">不加载 -
document.head或document.body返回null - 开发者工具里看到
#document下直接挂<p></p>或<div>,没有 <code>包裹实操建议:
- 手写 HTML 时,开头必须是
- 服务端模板(如 EJS、Jinja)中检查 layout 文件是否漏写了
标签 - 用
document.documentElement检查:如果它是null或undefined,说明 DOM 根缺失
和的隐式创建规则浏览器会尝试“修复”缺失的
或,但行为不可靠:- 没写
?浏览器自动插入一个空,但<meta charset>若写在它前面,会被移到新外——导致乱码 - 没写
?所有非内容被塞进隐式,但document.body可能延迟可访问(尤其 SSR 场景)
实操建议:
- 永远显式写出
和,哪怕内容为空 -
<meta charset="UTF-8">必须是中第一个标签(规范要求) - 避免依赖浏览器修复:Vue/React SSR 输出若漏掉
,hydration 会失败并报Mismatching childNodes
<title></title>放错位置的后果比你想象得更早<title></title>只能在内生效。放错位置(比如写在开头),会导致:- 页面标题栏显示为空或默认值(如 “Untitled”)
- 搜索引擎抓取不到 title,影响 SEO
- 部分浏览器(如 Safari iOS)不触发 history.state 更新
实操建议:
- 用 Linter 工具(如
eslint-plugin-html或html-validate)校验<title></title>是否在内 - 动态设置时用
document.title = "...",而非操作 DOM 节点——因为 DOM 中的<title></title>可能已被浏览器忽略 - SSR 模板中确认
<title></title>不被条件语句意外包裹在块里
真正容易被忽略的不是“要不要写结构标签”,而是“谁在生成它们”。构建工具(Vite、Webpack)、框架(Next.js、Nuxt)常自动生成外壳,一旦配置出错或手动覆盖模板,
层就可能残缺——这时连console.log(document)都看不出问题,得看document.documentElement是否为HTMLHtmlElement实例。 - 手写 HTML 时,开头必须是











