HTML 与 XHTML 的区别
本节将深入对比 HTML 和 XHTML 在语法规则上的具体差异,分析 XHTML 失败的根本原因,以及 HTML5 如何在兼容性和规范性之间找到平衡。
前置知识
阅读本节前,建议先了解:发展历史与版本
基础概念
HTML(HyperText Markup Language)和 XHTML(eXtensible HyperText Markup Language)都是用于构建网页内容的标记语言,但它们遵循不同的语法规范。HTML 基于 SGML 标准,允许宽松的语法;XHTML 基于 XML 标准,要求严格的语法。
简单来说:XHTML 是 HTML 的 XML 化版本。XHTML 的目标是让 HTML 文档也能作为 XML 文档被正确解析和处理。然而,由于 XML 的严格语法与 Web 的实际情况存在巨大差距,XHTML 最终走向了失败。
语法差异详解
标签闭合
这是 HTML 和 XHTML 最显著的差异。
HTML 允许部分标签省略闭合标签:
<!-- HTML 中合法:p 标签可以省略闭合 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>HTML 标签示例</title>
</head>
<body>
<p>第一个段落
<p>第二个段落
<p>第三个段落
</body>
</html>浏览器会自动补全这些未闭合的标签。
XHTML 要求所有标签必须显式闭合:
<!-- XHTML 中必须显式闭合 -->
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>XHTML 标签示例</title>
</head>
<body>
<p>第一个段落</p>
<p>第二个段落</p>
<p>第三个段落</p>
</body>
</html>对于没有内容的自闭合标签,HTML 和 XHTML 的写法也不同:
<!-- HTML 写法(推荐):不写斜杠 -->
<br>
<hr>
<img src="photo.jpg" alt="照片">
<input type="text">
<!-- XHTML 写法:必须有斜杠 -->
<br />
<hr />
<img src="photo.jpg" alt="照片" />
<input type="text" />大小写敏感
HTML 标签名和属性名不区分大小写:
<!-- HTML 中以下写法等价 -->
<HTML>
<BODY>
<DIV CLASS="box">内容</DIV>
<H1>标题</H1>
</BODY>
</HTML>XHTML 要求所有标签名和属性名必须使用小写(因为 XML 区分大小写):
<!-- XHTML 中只有小写是合法的 -->
<html>
<body>
<div class="box">内容</div>
<h1>标题</h1>
</body>
</html>
<!-- 错误!XHTML 中 <DIV> 和 <div> 是不同的标签 -->
<DIV>内容</DIV>属性值引号
HTML 在某些情况下可以省略属性值的引号(不推荐):
<!-- HTML 中可以运行但不推荐 -->
<input type=text name=username value=hello>
<a href=https://example.com>链接</a>
<!-- 推荐:始终使用引号 -->
<input type="text" name="username" value="hello">
<a href="https://example.com">链接</a>XHTML 要求属性值必须使用引号包裹:
<!-- XHTML:必须使用引号 -->
<input type="text" name="username" value="hello" />
<!-- 错误!XHTML 中不使用引号会导致解析失败 -->
<input type=text name=username />属性最小化
HTML 允许布尔属性只写属性名,不写值:
<!-- HTML 中合法的布尔属性简写 -->
<input type="checkbox" checked>
<input type="text" disabled>
<input type="text" readonly>
<option selected>默认选项</option>
<video autoplay muted loop>XHTML 要求所有属性必须有值,布尔属性写为 属性名="属性名":
<!-- XHTML 中布尔属性必须有值 -->
<input type="checkbox" checked="checked" />
<input type="text" disabled="disabled" />
<input type="text" readonly="readonly" />
<option selected="selected">默认选项</option>
<video autoplay="autoplay" muted="muted" loop="loop"></video>属性顺序
XHTML 有一个 HTML 中不存在的限制:属性名中不能出现相同字母的不同大小写形式。这在实践中极少遇到,但了解一下是有益的。
CDATA 段落
在 HTML 和 XHTML 中,<script> 和 <style> 标签内包含特殊字符(如 <、&)的处理方式不同:
HTML 中,<script> 和 <style> 的内容被视为原始文本,不需要转义:
<!-- HTML:script 内容不需要转义 -->
<script>
if (a < b && c > d) {
alert("a 小于 b");
}
</script>XHTML 中,由于是 XML 文档,< 和 & 必须被转义,或者使用 CDATA 段落:
<!-- XHTML 方式一:转义特殊字符 -->
<script>
//<![CDATA[
if (a < b && c > d) {
alert("a 小于 b");
}
//]]>
</script>
<!-- XHTML 方式二:使用 CDATA 段落(推荐) -->
<script>
//<![CDATA[
if (a < b && c > d) {
alert("a 小于 b");
}
//]]>
</script>文档声明和命名空间
HTML5 使用简洁的 DOCTYPE 声明:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>HTML 文档</title>
</head>
<body>
<p>HTML 文档不需要 XML 命名空间。</p>
</body>
</html>XHTML 需要更复杂的声明和 XML 命名空间:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>XHTML 文档</title>
</head>
<body>
<p>XHTML 文档需要 XML 命名空间声明。</p>
</body>
</html>差异汇总表
| 对比项 | HTML | XHTML |
|---|---|---|
| 基础标准 | SGML | XML |
| 标签闭合 | 部分标签可省略闭合 | 所有标签必须闭合 |
| 大小写 | 不区分 | 必须小写 |
| 属性引号 | 某些情况可省略 | 必须使用 |
| 布尔属性 | 可省略值(如 checked) | 必须有值(如 checked="checked") |
| 自闭合标签 | 不需要 /(<br>) | 必须有 /(<br />) |
| 脚本/样式中的特殊字符 | 不需要转义 | 需要 CDATA 或转义 |
| DOCTYPE | 简洁(<!DOCTYPE html>) | 冗长的 DTD 声明 |
| 命名空间 | 不需要 | 必须(xmlns) |
| 解析错误 | 容错解析,尽力显示 | 严格解析,一个错误可能导致整个页面失败 |
| MIME 类型 | text/html | application/xhtml+xml |
XHTML 失败的原因
XHTML 的初衷是好的——让 HTML 文档更加规范、易于机器解析。但为什么它最终失败了?
1. 严格的错误处理
XML 的错误处理策略是"遇到错误即停止"。如果 XHTML 页面中有一个未闭合的标签或缺少引号,整个页面就会显示为解析错误,而不是像 HTML 那样"尽力渲染"。
<!-- 一个小小的错误就导致 XHTML 页面完全不可用 -->
<div>
<p>这段文字有未闭合的 span
<span>标签
<!-- 缺少 </span> -->
</div>在 HTML 中,浏览器会尽力猜测你的意图并渲染页面。在 XHTML 中,浏览器会报错并停止显示。
2. MIME 类型问题
要真正以 XHTML 模式解析页面,服务器必须发送 application/xhtml+xml 的 MIME 类型。但 Internet Explorer(当时市场占有率最高的浏览器)不支持这个 MIME 类型,会弹出一个文件下载对话框而不是渲染页面。
# 正确的 XHTML MIME 类型
Content-Type: application/xhtml+xml; charset=utf-8
# IE 不支持上述类型,只能回退到 HTML 渲染
Content-Type: text/html; charset=utf-8这意味着大多数声称使用 XHTML 的网站实际上是以 text/html 提供给浏览器的,浏览器只是以 HTML 模式解析它们——也就是说,XHTML 的严格规范从未真正生效。
3. 开发体验差
严格语法要求增加了开发成本:
<!-- 开发者实际写出的 HTML(tag soup) -->
<P class=box>标题
<ul>
<LI>项目 1
<li>项目 2
</UL>
<!-- XHTML 要求开发者改写成 -->
<p class="box">标题</p>
<ul>
<li>项目 1</li>
<li>项目 2</li>
</ul>要求所有开发者(包括非专业的内容编辑)都严格遵守 XML 规范,在现实世界中是不切实际的。
4. 发展方向分歧
XHTML 2.0 试图彻底重新设计 HTML,甚至放弃了 <img>、<a> 等核心标签,用全新的标签替代。这种"推倒重来"的方案完全不顾向后兼容性:
| 被废弃的标签 | XHTML 2.0 替代方案 | 问题 |
|---|---|---|
<img> | <object> | 语义不明确 |
<a> | 任何元素上加 href 属性 | 过于灵活,反而混乱 |
<b>、<i> | <strong>、<em> 或 CSS | 限制了灵活性 |
而 WHATWG 的 HTML5 路线选择了"进化"而非"革命"——保留所有已有的标签和用法,在其基础上新增特性。
HTML5 如何继承 XHTML 的优点
HTML5 采用了"兼容但不纵容"的策略。它保留了 HTML 的宽松语法以确保兼容性,但同时引入了 XHTML 中好的实践:
推荐但非强制的规范
HTML5 推荐开发者遵循 XHTML 的良好实践,但不强制:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>HTML5 推荐 XHTML 风格</title>
</head>
<body>
<!-- 推荐:标签闭合 -->
<p>段落内容</p>
<!-- 推荐:小写标签 -->
<div class="container">
<h1>标题</h1>
</div>
<!-- 推荐:属性值加引号 -->
<a href="https://example.com" title="示例">链接</a>
<!-- 推荐:自闭合标签不写斜杠 -->
<br>
<img src="photo.jpg" alt="照片">
<input type="text" required>
<!-- HTML5 也允许不闭合的 p 标签,但不推荐 -->
<p>不闭合也能运行
<p>但不推荐这样做
</body>
</html>保留的 XHTML 优点
| XHTML 优点 | HTML5 中的体现 |
|---|---|
| 严格语法 | 作为最佳实践推荐,不强制 |
| 小写标签 | 所有规范和文档统一使用小写 |
| 属性引号 | 强烈推荐使用引号 |
| 语义化 | 更丰富的语义化标签(header、nav、main 等) |
| 可机器解析 | DOM 标准化 + 微数据/微格式 |
| 国际化 | 完善的 lang 属性和 UTF-8 支持 |
| 无障碍 | ARIA 属性和语义标签增强 |
实战示例
下面的示例展示了同一个页面在 XHTML 1.0 严格模式和 HTML5 中的写法差异:
<!-- ============================================================ -->
<!-- XHTML 1.0 严格模式(已过时,仅供对比) -->
<!-- ============================================================ -->
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>联系表单</title>
</head>
<body>
<h1>联系表单</h1>
<form id="contactForm" action="/submit" method="post">
<fieldset>
<legend>个人信息</legend>
<p>
<label for="name">姓名:</label>
<input type="text" id="name" name="name" size="30" />
</p>
<p>
<label for="email">邮箱:</label>
<input type="text" id="email" name="email" size="40" />
</p>
<p>
<label for="message">留言:</label>
<textarea id="message" name="message" rows="6" cols="40">在这里输入留言...</textarea>
</p>
<p>
<input type="submit" value="提交" />
<input type="reset" value="重置" />
</p>
</fieldset>
</form>
</body>
</html><!-- ============================================================ -->
<!-- HTML5 写法(当前推荐) -->
<!-- ============================================================ -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>联系表单</title>
</head>
<body>
<h1>联系表单</h1>
<form action="/submit" method="post">
<fieldset>
<legend>个人信息</legend>
<!-- HTML5 新类型:email 自动验证格式 -->
<p>
<label for="name">姓名:</label>
<input type="text" id="name" name="name"
required minlength="2" placeholder="请输入姓名">
</p>
<p>
<label for="email">邮箱:</label>
<input type="email" id="email" name="email"
required placeholder="example@mail.com">
</p>
<p>
<label for="message">留言:</label>
<textarea id="message" name="message" rows="6"
placeholder="在这里输入留言..." required></textarea>
</p>
<p>
<button type="submit">提交</button>
<button type="reset">重置</button>
</p>
</fieldset>
</form>
</body>
</html>从 XHTML 迁移到 HTML5
如果你有 XHTML 的背景知识,迁移到 HTML5 很简单:去掉冗长的 DOCTYPE、去掉 xmlns、去掉自闭合标签的 /、使用 <meta charset="UTF-8"> 替代 http-equiv 写法。HTML5 鼓励你保持 XHTML 良好的编码习惯。
注意事项
- 不要再编写 XHTML 1.x 文档——它已是历史产物
- 不要在 HTML5 文档的自闭合标签上加
/(如<br />),虽然浏览器能处理,但不规范 - HTML5 文档应使用
text/htmlMIME 类型,不要使用application/xhtml+xml - XHTML 2.0 已被正式放弃,不存在任何浏览器支持
- 尽管浏览器对不规范的 HTML 有容错能力,但始终应该编写规范的代码
最佳实践
- 采用 HTML5 语法,但保持 XHTML 风格的编码规范(小写、引号、闭合标签)
- 使用
<!DOCTYPE html>声明,这是唯一推荐的文档类型 - 为
<html>标签添加lang属性声明语言 - 使用
<meta charset="UTF-8">声明字符编码 - 编写格式良好的 HTML,既便于阅读也便于工具处理
- 使用 HTML 验证工具(如 W3C Validator)定期检查代码
下一节
继续学习:第一个 HTML 页面