Skip to content

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
<!-- HTML 中合法:p 标签可以省略闭合 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>HTML 标签示例</title>
</head>
<body>
  <p>第一个段落
  <p>第二个段落
  <p>第三个段落
</body>
</html>

浏览器会自动补全这些未闭合的标签。

XHTML 要求所有标签必须显式闭合:

html
<!-- 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
<!-- 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 中以下写法等价 -->
<HTML>
<BODY>
  <DIV CLASS="box">内容</DIV>
  <H1>标题</H1>
</BODY>
</HTML>

XHTML 要求所有标签名和属性名必须使用小写(因为 XML 区分大小写):

html
<!-- XHTML 中只有小写是合法的 -->
<html>
<body>
  <div class="box">内容</div>
  <h1>标题</h1>
</body>
</html>

<!-- 错误!XHTML 中 <DIV> 和 <div> 是不同的标签 -->
<DIV>内容</DIV>

属性值引号

HTML 在某些情况下可以省略属性值的引号(不推荐):

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 要求属性值必须使用引号包裹:

html
<!-- XHTML:必须使用引号 -->
<input type="text" name="username" value="hello" />

<!-- 错误!XHTML 中不使用引号会导致解析失败 -->
<input type=text name=username />

属性最小化

HTML 允许布尔属性只写属性名,不写值:

html
<!-- HTML 中合法的布尔属性简写 -->
<input type="checkbox" checked>
<input type="text" disabled>
<input type="text" readonly>
<option selected>默认选项</option>
<video autoplay muted loop>

XHTML 要求所有属性必须有值,布尔属性写为 属性名="属性名"

html
<!-- 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
<!-- HTML:script 内容不需要转义 -->
<script>
  if (a < b && c > d) {
    alert("a 小于 b");
  }
</script>

XHTML 中,由于是 XML 文档,<& 必须被转义,或者使用 CDATA 段落:

html
<!-- XHTML 方式一:转义特殊字符 -->
<script>
//<![CDATA[
  if (a &lt; b &amp;&amp; c &gt; d) {
    alert("a 小于 b");
  }
//]]>
</script>

<!-- XHTML 方式二:使用 CDATA 段落(推荐) -->
<script>
//<![CDATA[
  if (a < b && c > d) {
    alert("a 小于 b");
  }
//]]>
</script>

文档声明和命名空间

HTML5 使用简洁的 DOCTYPE 声明:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>HTML 文档</title>
</head>
<body>
  <p>HTML 文档不需要 XML 命名空间。</p>
</body>
</html>

XHTML 需要更复杂的声明和 XML 命名空间:

html
<!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>

差异汇总表

对比项HTMLXHTML
基础标准SGMLXML
标签闭合部分标签可省略闭合所有标签必须闭合
大小写不区分必须小写
属性引号某些情况可省略必须使用
布尔属性可省略值(如 checked必须有值(如 checked="checked"
自闭合标签不需要 /<br>必须有 /<br />
脚本/样式中的特殊字符不需要转义需要 CDATA 或转义
DOCTYPE简洁(<!DOCTYPE html>冗长的 DTD 声明
命名空间不需要必须(xmlns
解析错误容错解析,尽力显示严格解析,一个错误可能导致整个页面失败
MIME 类型text/htmlapplication/xhtml+xml

XHTML 失败的原因

XHTML 的初衷是好的——让 HTML 文档更加规范、易于机器解析。但为什么它最终失败了?

1. 严格的错误处理

XML 的错误处理策略是"遇到错误即停止"。如果 XHTML 页面中有一个未闭合的标签或缺少引号,整个页面就会显示为解析错误,而不是像 HTML 那样"尽力渲染"。

html
<!-- 一个小小的错误就导致 XHTML 页面完全不可用 -->
<div>
  <p>这段文字有未闭合的 span
  <span>标签
  <!-- 缺少 </span> -->
</div>

在 HTML 中,浏览器会尽力猜测你的意图并渲染页面。在 XHTML 中,浏览器会报错并停止显示。

2. MIME 类型问题

要真正以 XHTML 模式解析页面,服务器必须发送 application/xhtml+xml 的 MIME 类型。但 Internet Explorer(当时市场占有率最高的浏览器)不支持这个 MIME 类型,会弹出一个文件下载对话框而不是渲染页面。

http
# 正确的 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
<!-- 开发者实际写出的 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 的良好实践,但不强制:

html
<!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 中的写法差异:

html
<!-- ============================================================ -->
<!-- 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>
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/html MIME 类型,不要使用 application/xhtml+xml
  • XHTML 2.0 已被正式放弃,不存在任何浏览器支持
  • 尽管浏览器对不规范的 HTML 有容错能力,但始终应该编写规范的代码

最佳实践

  • 采用 HTML5 语法,但保持 XHTML 风格的编码规范(小写、引号、闭合标签)
  • 使用 <!DOCTYPE html> 声明,这是唯一推荐的文档类型
  • <html> 标签添加 lang 属性声明语言
  • 使用 <meta charset="UTF-8"> 声明字符编码
  • 编写格式良好的 HTML,既便于阅读也便于工具处理
  • 使用 HTML 验证工具(如 W3C Validator)定期检查代码

下一节

继续学习:第一个 HTML 页面

参考链接