Skip to content

文档结构三件套 ​

先解决一个问题:浏览器从哪里开始解析? ​

先建立一个独立文件夹,把下面完整内容以 UTF-8 保存为 structure.html。确认扩展名不是 .html.txt,然后拖入浏览器地址栏。修改后先保存文件,再刷新浏览器;编辑器里的修改不会自动出现在已打开的页面里。本篇不需要服务器、CSS 或 JavaScript 开发经验。

这是明确写出根元素、元信息与正文的入门模板。浏览器能补全一些省略的结构,但初学时把它们写全,更容易区分作者的意图和解析器的处理结果。

html
<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <title>结构实验</title>
  </head>
  <body>
    <main>
      <h1>一篇文章</h1>
      <p>这是正文。</p>
    </main>
  </body>
</html>

<!doctype html> 是文档类型声明,它让浏览器使用标准模式解析页面;它不是可以被 CSS 选中的元素。html 是文档根元素,head 放不会直接作为页面正文显示的元信息,body 放文档的可见内容。lang 是根元素上的属性,帮助辅助技术和语言相关功能判断页面语言。

把 <html lang="zh-CN"> 拆开看:html 是元素名称,lang 是属性名,双引号里的文字是属性值。</html> 是结束标签。meta 属于空元素,不写 </meta>。title 的文字显示在浏览器标签页中,而 h1 和 p 的文字属于正文。先分别观察标签页和页面,确认它们没有混在一起。

解析结果不是一串标签,而是一棵树 ​

上面的 main 是 body 的子元素,h1 和 p 是 main 的子元素。缩进不是浏览器建立父子关系的依据,开始标签和结束标签才是;但保持缩进能让作者发现嵌套错误。

html
<p>你好,<strong>世界</strong>。</p>

这里有一个 p 元素、一个文本节点、一个 strong 元素和另一个文本节点。strong 没有把文本变成“粗体组件”,它表达的是重要性;视觉样式应由 CSS 决定。

变化一个条件观察差异 ​

把 lang="zh-CN" 改成 lang="en",页面看起来通常没有变化,但屏幕阅读器、拼写检查和翻译工具会得到不同的语言提示。把 main 改成 div,视觉上也可能不变,但文档的语义导航信息会减少。HTML 结构的价值不只在当前截图里。

运行实验 ​

  1. 将最小页面保存为 structure.html 并直接在浏览器打开。
  2. 在 Elements 面板中展开 html > body > main。
  3. 删除 <!doctype html>,重新加载并查看文档模式;在控制台运行 document.compatMode,比较结果。
  4. 把 main 改为 div,保持页面文字不变,记录视觉结果没有变化但语义结构发生了什么变化。

第三步中的 document 指当前文档,点号后的 compatMode 是文档模式信息。这里只把这行表达式作为观察工具,无需先学习函数和变量。保留短 doctype 时应得到 "CSS1Compat";从本例删掉它并刷新后应得到 "BackCompat"。恢复 doctype 后再刷新,结果应恢复。仅在 Elements 面板编辑已经解析好的树,不等于让浏览器重新选择文档模式。

CSS1Compat 也可能出现在有限怪异模式中,不能仅凭这个字符串区分所有历史模式。短 doctype 的作用是避免触发旧的兼容布局行为;它不会下载一个“HTML5 引擎”,也不能保证你编写的其他标记都合法。

为什么源码没写,Elements 里却有 ​

另存一个独立文件 implicit.html,只写下面内容:

html
<!doctype html>
<title>自动补全实验</title>
<p>只有一个段落。</p>

打开后查看 Elements:仍然有 html、head 和 body。解析器读到 title 时把它放入头部,读到段落时建立正文;这些结构不是编辑器偷偷写进磁盘的。对照“查看网页源代码”和 Elements,可以分别看到输入文本和解析后的树。某些标签允许在特定条件下省略,不等于可以任意省略全部结束标签。

再把该文件的最后一行替换为这个刻意错误的片段:

html
<p>前半段<div>插入的块</div>后半段</p>

你可能期望 div 位于 p 内,但段落不允许这样包含它。Elements 中,第一个 p 只含“前半段”,div 成为兄弟,“后半段”在外面,末尾还会出现一个空 p。浏览器遇到 div 起始标签时结束了段落,随后孤立的段落结束标签又触发修复。页面能显示,只证明解析器能继续工作,不能证明原始嵌套正确。把这个内容改为两个段落,中间单独放 div,即可使源码与实际结构一致。

常见错误 ​

  • 把 doctype 写成普通元素或放进 body。
  • 让页面拥有多个无关的顶层可见容器,却没有表达主要内容的关系。
  • 用缩进“修复”未闭合标签;缩进只能帮助阅读,不能改变解析规则。
  • 用 div 代替所有语义元素,再依赖 CSS 和脚本补回行为。

练习 ​

创建一个包含页眉、主要内容和页脚的页面。要求:根元素声明中文,主要内容只能有一个 main,文章标题使用一个 h1,并在开发者工具中指出每个区域在 DOM 树中的父子关系。不要先看答案;先用 Elements 面板验证自己的结构。

本题只使用三个区域元素:header 表示引导内容,main 表示页面主要内容,footer 表示页脚。将它们写成 body 下的三个兄弟;把标题与段落放在 main 内。分别改变缩进和真正的嵌套,说明哪一次改变了父子关系。再建立无 doctype 的副本,记录两份文件的 compatMode,并解释为什么视觉相似不能证明文档模式相同。

完成后核对答案。

继续阅读 ​

下一篇会解释 head 中的元信息,以及为什么字符编码和 viewport 必须在页面早期声明:head 里的元信息。

用心记录每一步成长