HTML语法学习文档(一)

1.HTML 演进、标准与底层模型

目录

[1.HTML 演进、标准与底层模型](#1.HTML 演进、标准与底层模型)

[1.1 HTML 发展史与标准化组织](#1.1 HTML 发展史与标准化组织)

[1.1.1 从 HTML2.0 到 HTML5 的重大变革回顾](#1.1.1 从 HTML2.0 到 HTML5 的重大变革回顾)

[HTML 版本演进总览](#HTML 版本演进总览)

[1.1.2 标准之争:W3C (HTML5) 与 WHATWG (Living Standard) 的分合与现状](#1.1.2 标准之争:W3C (HTML5) 与 WHATWG (Living Standard) 的分合与现状)

两大组织标准制定理念对比

[1.1.3 浏览器渲染引擎前缀历史:为何需要 -webkit- 及现代标准化现状](#1.1.3 浏览器渲染引擎前缀历史:为何需要 -webkit- 及现代标准化现状)

常见浏览器引擎前缀对照表

[1.2 DOM 核心模型与节点类型](#1.2 DOM 核心模型与节点类型)

[1.2.1 DOM 树构建原理:字节流 → 分词器 → Tokens → 节点 → 对象模型](#1.2.1 DOM 树构建原理:字节流 → 分词器 → Tokens → 节点 → 对象模型)

[DOM 构建流程解析](#DOM 构建流程解析)

[1.2.2 节点类型深度解析:Element, Text, Comment, DocumentType 及其内存结构](#1.2.2 节点类型深度解析:Element, Text, Comment, DocumentType 及其内存结构)

核心节点类型与属性对比

[1.2.3 HTML 中的"空白字符处理"与文本节点规范化](#1.2.3 HTML 中的“空白字符处理”与文本节点规范化)

空白符处理机制对比

[1.3 文档模式与渲染触发](#1.3 文档模式与渲染触发)

[1.3.1 的作用机制:触发标准模式 vs 怪异模式](#1.3.1 的作用机制:触发标准模式 vs 怪异模式)

文档模式对渲染的影响

[1.3.2 文档模式对 CSS 盒模型和 JS 行为的历史遗留影响](#1.3.2 文档模式对 CSS 盒模型和 JS 行为的历史遗留影响)

盒模型差异对比


1.1 HTML 发展史与标准化组织

1.1.1 从 HTML2.0 到 HTML5 的重大变革回顾

Web 的发展并非一蹴而就,而是一段不断修补与进化的历程。

从早期的静态文档展示到如今的富应用平台,HTML 版本的每一次迭代都映射着互联网技术的跃迁。

要理解现在的 Web,必须先梳理清楚这些关键节点的变化。

HTML 版本演进总览

|---------------|----------|--------------------|------------------------------------|-----------------------|
| 版本 | 发布年份 | 核心特征 | 代表性标签 / 能力 | 遗留问题 / 现状 |
| HTML 2.0 | 1995 | 第一个标准化版本 | <form>, <input> | 布局能力极弱,依赖表格 |
| HTML 4.01 | 1999 | 严格分离样式与结构 | CSS 引入,强调语义 | 缺乏原生多媒体支持,标签复杂 |
| XHTML 1.0 | 2000 | XML 语法严谨性 | 标签必须闭合,小写 | 过于严格,容错率低,浏览器解析慢 |
| HTML5 | 2014 | 语义化、原生 API | <video>, <canvas>, <article> | 当前主流标准,持续进化中 |

在 HTML4 时代,为了实现页面布局,开发者不得不滥用 <table> 标签,导致代码臃肿且难以维护。

HTML5 之前的典型布局写法:

html 复制代码
<table width="100%">

  <tr>

    <td colspan="2">Header</td>

  </tr>

  <tr>

    <td width="200">Sidebar</td>

    <td>Content</td>

  </tr>

</table>

HTML5 的出现彻底改变了这一局面,它不仅引入了原生的多媒体支持,还通过语义化标签让文档结构更加清晰。

HTML5 的语义化布局写法(推荐):

html 复制代码
<header>Header</header>

<div class="container">

  <aside>Sidebar</aside>

  <main>Content</main>

</div>

<footer>Footer</footer>

这一过程就像是建房技术的升级:

早期是用石头和泥土(HTML 2.0)随意堆砌,

后来开始使用砖块并有了严格的图纸(XHTML),

而现在是使用预制件和模块化框架(HTML5),

不仅建得快,而且结构清晰,抗震性强。

1.1.2 标准之争:W3C (HTML5) 与 WHATWG (Living Standard) 的分合与现状

标准制定的过程往往充满博弈。

很长一段时间里,HTML 的未来走向并不明朗,主要因为两个核心组织------W3C 和 WHATWG------对 Web 发展的理念存在分歧。

理解这种关系,有助于明白为什么现在的 HTML 标准显得有些"特殊"。

这就好比是"学院派"与"实战派"的争论。

W3C 像是一个严谨的学术委员会,主张制定像书一样出版、版本号固定的标准(如 HTML5, HTML5.1);

而 WHATWG 则更像是一群激进的工程师组成的敏捷开发小组,主张标准应该是像软件一样持续更新的"活文档"(Living Standard)。

两大组织标准制定理念对比

|----------|---------------------------------------------------------------|-----------------------------------------------------------------|
| 维度 | W3C (World Wide Web Consortium) | WHATWG (Web Hypertext Application Technology Working Group) |
| 核心理念 | 版本化控制 | 活标准 |
| 产出形式 | HTML5, HTML5.1 等快照版本 | 单一、持续更新的 HTML 标准 |
| 关注点 | 规范的严谨性与完整性 | 浏览器的实现细节与互操作性 |
| 现状 | 2019 年与 WHATWG 达成和解 ,目前主要负责 CSS、无障碍等非 HTML 规范 | 主导 HTML 标准的制定 ,所有主流浏览器均遵循其规范 |

虽然双方曾一度分道扬镳,导致出现过两个并行的 HTML 标准,但最终还是殊途同归。

现在的局面是:

WHATWG 负责"造车",持续维护 HTML 引擎的构造逻辑;

W3C 负责"定交规",将 HTML 的某些部分作为快照用于认证或参考。

html 复制代码
<!-- 解释:在实际开发中,代码并不需要标注遵循哪个组织的标准,只需遵循浏览器的实现即可 -->

<!DOCTYPE html>

<html lang="zh-CN">

<head>

    <meta charset="UTF-8">

    <!-- 解释:这里的 DOCTYPE 不再指向某个具体的 DTD 文件,而是触发浏览器的标准模式 -->

    <title>Living Standard Example</title>

</head>

<body>

    <script>

        // 解释:现代浏览器的 API 更新速度极快,基本跟随 WHATWG 的规范

        if ('serviceWorker' in navigator) {

            console.log('遵循 Living Standard 的现代 API 可用');

        }

    </script>

</body>

</html>

这场"标准之争"的平息,对开发者来说绝对是利好消息。

意味着不再需要担心代码在浏览器 A 里是对的,到了浏览器 B 里因为标准不同而报错,Web 的兼容性基石因此变得更加稳固。

1.1.3 浏览器渲染引擎前缀历史:为何需要 -webkit- 及现代标准化现状

在 CSS3 普及的初期,浏览器的渲染引擎对于新特性的支持步调并不一致。

为了让开发者能提前体验新功能,同时也为了避免实验室阶段的特性破坏已有标准,浏览器厂商引入了"前缀"机制。

这就像是给新药贴上"临床试验中"的标签,既能让急需的人试用,又能说明其尚未正式上市。

常见浏览器引擎前缀对照表

|--------------|----------------|----------------------------------|
| 前缀 | 对应浏览器内核 | 代表浏览器 |
| -webkit- | Webkit (Blink) | Chrome, Safari, Edge (新版), Opera |
| -moz- | Gecko | Firefox |
| -ms- | Trident | IE (Internet Explorer) |
| -o- | Presto (旧版) | Opera (旧版) |

这种机制虽然在当时促进了技术革新,但也给开发者带来了沉重的负担。

同一个圆角效果,往往要写四行代码,还要考虑各浏览器实现的细微差异。

html 复制代码
.box {

    /* 解释:早期为了实现圆角,需要编写大量冗余代码 */

    -webkit-border-radius: 10px; /* Chrome, Safari */

    -moz-border-radius: 10px;    /* Firefox */

    -ms-border-radius: 10px;     /* IE */

    border-radius: 10px;         /* 标准属性写法 */

}

/* 解释:现代开发中,绝大多数属性(如 Flexbox, Grid)已全兼容,无需前缀 */

.modern-box {

    /* 解释:直接使用标准属性即可,除非是极度前沿的实验性特性 */

    display: flex;

    backdrop-filter: blur(10px); /* 解释:部分较新属性可能仍需 -webkit- 支持 */

}

如今,随着 W3C 标准化流程的加快和浏览器厂商的默契,大部分常用特性(Flexbox, Grid, Transform 等)已经去掉了前缀。

现在的最佳实践是:

优先使用标准属性,仅在特定需要兼容旧版或实验性特性时才添加前缀,通常配合 Autoprefixer 等工具自动处理,就像是用翻译软件自动处理方言一样,既高效又准确。

1.2 DOM 核心模型与节点类型

1.2.1 DOM 树构建原理:字节流 → 分词器 → Tokens → 节点 → 对象模型

当浏览器接收到服务器返回的 HTML 数据时,它看到的并不是页面,而是一连串枯燥的字节流。

DOM 树的构建过程,实际上就是浏览器将这些"原材料"逐步加工成"结构化蓝图"的过程。

这就像阅读一本小说,眼睛扫描的是文字(字节流),大脑将其拆解为词汇和句子(Tokens),最后在脑海中构建出人物关系和剧情场景(DOM 树)。

DOM 构建流程解析

|---------|---------|-----------------|------------------------------|
| 阶段 | 输入 | 处理动作 | 输出 |
| 字节流 | 网络响应的字节 | 识别字符编码(如 UTF-8) | 字符流 |
| 分词 | 字符流 | 将字符转换为有意义的标记 | Tokens (如 <div>, StartTag) |
| 解析 | Tokens | 根据标签关系建立层级 | DOM 节点 |
| 对象化 | DOM 节点 | 封装属性和方法 | JavaScript 对象 |

在这个过程中,<html> 是根节点,<head> 和 <body> 是其子节点。

解析器通常是边加载边解析,这也是为什么将 <script> 标签放在 <body> 底部可以提高性能的原因------不会阻塞页面的初步渲染。

html 复制代码
<!-- 解释:这是一个简单的 HTML 结构,用于演示 DOM 如何构建 -->

<!DOCTYPE html>

<html>

  <body>

    <div id="app">

      <p>Hello World</p>

    </div>

    <script>

      // 解释:脚本执行时,上面的 DOM 树通常已经构建完毕

      const app = document.getElementById('app');

      console.log(app.nodeName); // 输出: DIV

    </script>

  </body>

</html>

这就好比搭积木,必须先有底座(字节流转字符),再识别积木块的形状(分词成 Token),最后按图纸拼装成城堡(DOM 树)。

每一步都环环相扣,任何一个环节出错(比如标签未闭合),都可能导致整个城堡搭建失败或变形。

1.2.2 节点类型深度解析:Element, Text, Comment, DocumentType 及其内存结构

DOM 树不仅仅是标签的堆砌,它是由不同类型的"节点"组成的复杂网络。

在 JavaScript 的眼中,HTML 里的标签、文字、注释甚至是文档类型声明,都是内存中不同的对象实例。

如果把网页比作一个公司,那么 Element 节点就是部门经理,Text 节点是干活的员工,Comment 节点是便签上的备忘录,而 DocumentType 则是公司的注册许可证。

核心节点类型与属性对比

|----------------------------|----------------------|---------------------|--------------------------------|
| 节点类型 | nodeType 常量值 | nodeName 示例 | 内存结构特征 |
| Element ( 元素 ) | 1 | DIV, SPAN, P | 拥有属性、子节点,对应 HTML 标签 |
| Text ( 文本 ) | 3 | #text | 纯文本内容,叶子节点,无子节点 |
| Comment ( 注释 ) | 8 | #comment | 注释内容,通常不显示,调试用 |
| DocumentType | 10 | html | <!DOCTYPE html> 声明,包含 DTD 信息 |

开发者最常打交道的是 Element 节点,但在处理文本内容时,往往会忽略 Text 节点的存在。

例如

html 复制代码
<div>你好</div>

内部的"你好"就是一个 Text 节点,它是 div 元素节点的子节点。

html 复制代码
<div id="container">

  <!-- 解释:这是一个注释节点 -->

  文本内容

  <span>标签内文本</span>

</div>

<script>

  const container = document.getElementById('container');

  // 解释:遍历子节点查看不同类型

  container.childNodes.forEach(node => {

    switch(node.nodeType) {

      case Node.ELEMENT_NODE:

        console.log('找到元素节点:', node.nodeName);

        break;

      case Node.TEXT_NODE:

        // 解释:通常这里包含换行符和空格等空白符

        console.log('找到文本节点:', node.textContent.trim());

        break;

      case Node.COMMENT_NODE:

        console.log('找到注释节点:', node.nodeValue);

        break;

    }

  });

</script>

理解节点类型对于精准操作 DOM 至关重要。

比如,使用 children 属性只会获取 Element 类型的子节点,而 childNodes 则会获取所有类型的节点(包括换行产生的空白文本节点)。

这就好比找员工时,children 是只找正式编制的经理,而 childNodes 则是把清洁工和临时工都算进去了。

1.2.3 HTML 中的"空白字符处理"与文本节点规范化

在编写 HTML 代码时,为了美观,开发者通常会对代码进行缩进和换行。

然而,这些为了"人类可读"而存在的空白符(空格、换行、制表符),在浏览器解析 DOM 时,往往会变成实实在在的 Text 节点。

这种现象如果不加以处理,可能会导致 CSS 布局出现莫名其妙的间隙,或者 JavaScript 遍历节点时出现逻辑错误。

这就像是打包行李,本来以为只有几件衣服,结果包装袋里的气泡垫(空白字符)也占了半箱空间。

空白符处理机制对比

|-----------------|-----------------------|-----------------------------------|
| 场景 | 浏览器默认行为 | 开发者处理策略 |
| 代码格式化 | 将换行和缩进解析为空白 Text 节点 | 使用 normalize() 合并或 white-space 控制 |
| 行内元素间隙 | 多个行内元素间的换行产生约 4px 的空隙 | 设置 font-size: 0 或使用 Flexbox 布局 |
| JS 获取文本 | 包含首尾的换行符 | 使用 textContent.trim() 清理 |

当多个 Text 节点相邻时,DOM 并不会自动合并它们,除非显式调用方法。

html 复制代码
<ul id="list">

  <!-- 解释:li 之间的换行在 DOM 中会产生空白文本节点 -->

  <li>Item 1</li>

  <li>Item 2</li>

  <li>Item 3</li>

</ul>

<script>

  const list = document.getElementById('list');

  // 解释:输出子节点数量,可能大于 3(包含空白文本节点)

  console.log('原始子节点数:', list.childNodes.length);

  // 解释:规范化文本节点,将相邻的文本节点合并为一个

  list.normalize();

  // 解释:遍历时忽略纯空白节点,只处理元素节点

  const items = Array.from(list.childNodes).filter(node =>

    node.nodeType === Node.ELEMENT_NODE

  );

  items.forEach(item => console.log(item.textContent));

</script>

文本节点规范化就像是整理凌乱的线团,将散落的短线头拼接成一根长线。

在处理用户输入或动态生成的 HTML 片段时,调用 normalize() 可以有效减少内存占用,并避免后续遍历节点时出现意外错误,保证 DOM 结构的干净整洁。

1.3 文档模式与渲染触发

1.3.1 <!DOCTYPE html> 的作用机制:触发标准模式 vs 怪异模式

在 HTML4 及之前的版本中,页面顶部通常会有一长串复杂的 <!DOCTYPE> 声明。

而在 HTML5 中,这行声明被简化为 <!DOCTYPE html>。

这行代码虽然看起来不起眼,但它却是浏览器渲染行为的"指挥棒"。

它的核心作用只有一个:

告诉浏览器是用"现代标准"来渲染页面,还是用"旧时代的兼容逻辑"来渲染页面。后者被称为"怪异模式"。

文档模式对渲染的影响

|------------|-------------------------------------|---------------------------|-----------------------------|
| 模式 | 触发条件 | 渲染行为 | 适用场景 |
| 标准模式 | 包含完整或简化的 <!DOCTYPE> | 严格遵循 W3C 规范 | 现代 Web 开发(默认选择) |
| 怪异模式 | 缺少 DOCTYPE 或使用旧版 HTML/XHTML DOCTYPE | 模拟 IE5/旧版 Netscape 的非标准行为 | 维护极其古老的遗留系统 |
| 接近标准模式 | 严格 XHTML 过渡型 DOCTYPE 等 | 大部分标准,仅对表格处理宽松 | 极少见,特定过渡时期页面 |

如果没有 <!DOCTYPE html>,浏览器会认为这是一个古老的页面,从而进入怪异模式。

在怪异模式下,浏览器会故意模仿旧时的 Bug,以确保那些在 1999 年写的页面在今天看起来依然"没有崩"。

html 复制代码
<!-- 解释:必须将此声明放在 HTML 文件的第一行,且前面不能有空格 -->

<!DOCTYPE html>

<html lang="zh-CN">

<head>

  <meta charset="UTF-8">

  <title>标准模式示例</title>

  <style>

    .box {

      /* 解释:在标准模式下,宽高仅指内容区 */

      width: 200px;

      padding: 20px;

      border: 5px solid black;

    }

  </style>

</head>

<body>

  <div class="box">标准模式盒子</div>

</body>

</html>

这就像是交通信号灯,<!DOCTYPE html> 就是绿灯,告诉浏览器放心大胆地按现代交通规则行驶。

如果没有它,浏览器就会以为回到了马车时代,启动一套完全不同的交通逻辑(虽然为了兼容性保留了这套逻辑,但在现代开发中应极力避免)。

1.3.2 文档模式对 CSS 盒模型和 JS 行为的历史遗留影响

文档模式最直接影响的就是 CSS 的盒模型。

在标准模式(Standards Mode)下,width 属性仅指内容区域的宽度;而在怪异模式(Quirks Mode)下,width 属性包含了内容、内边距和边框的总宽度。

这种差异会导致同样的 CSS 代码在不同模式下展示出的尺寸截然不同。

盒模型差异对比

|-----------------------|-------------------------|----------------------------|
| 属性 | 标准模式 | 怪异模式 |
| 盒模型类型 | content-box (W3C 标准盒模型) | border-box (IE 盒模型) |
| Width 计算 | 仅 Content | Content + Padding + Border |
| 设置 box-sizing | 默认为 content-box | 默认模拟 border-box |

除了 CSS 之外,文档模式还会影响 JavaScript 的行为。

例如,在没有 DOCTYPE 的文档中:

某些浏览器可能允许通过 ID 直接访问元素(如 myDiv.innerText)

而非标准写法 document.getElementById('myDiv').innerText。

css 复制代码
/* 解释:为了消除文档模式带来的不确定性,现代开发的最佳实践是强制重置盒模型 */

*, *::before, *::after {

  /* 解释:border-box 让 padding 和 border 不会撑大设定好的盒子宽度,更符合直觉 */

  box-sizing: border-box;

}

.container {

  /* 解释:无论是哪种模式,现在都统一了计算逻辑:总宽 = 设定的 width */

  width: 100%;

  padding: 15px;

}

这种差异就像是"米"和"厘米"的区别。

标准模式要求精确计算米数(内容宽),怪异模式则把周围包装皮也算进米数里。

现代开发通过全局设置 box-sizing: border-box,实际上就是把浏览器的计算逻辑强行统一到了更直观、更方便的"怪异模式"逻辑上,消除了历史包袱带来的混乱。

相关推荐
Cache技术分享2 小时前
322. Java Stream API - 使用 Finisher 对 Collector 结果进行后处理
前端·后端
承渊政道2 小时前
C++学习之旅【C++继承概念指南与核心内容介绍】
c语言·开发语言·c++·笔记·学习·visual studio
3GPP仿真实验室2 小时前
6G 物理层变天AFDM:与其在 OFDM 的死胡同里撞墙,不如换个坐标系“折叠”世界
前端
Jing_Rainbow2 小时前
【React-9/Lesson93(2025-12-30)】React Hooks 深度解析:从基础到实战🎯
前端·javascript·react.js
GeminiJM2 小时前
LangGraph 源码学习笔记
linux·笔记·学习·langchain
We་ct2 小时前
LeetCode 2. 两数相加:链表经典应用题详解
前端·算法·leetcode·链表·typescript
babe小鑫2 小时前
大专应用统计学专业学习数据分析的实用性分析
学习·数据挖掘·数据分析
简佐义的博客2 小时前
15万单细胞、19种实体瘤:系统学习血管内皮细胞泛癌的单细胞与空间转录组联合分析思路
人工智能·学习
芝加哥兔兔养殖场2 小时前
前端/iOS开发者必备工具软件合集
前端·ios