第一次写XHTML时,我盯着浏览器里那个光秃秃的文档树发呆。明明写了完整的HTML结构,却只看到"This XML file does not appear to have any style information associated with it"的警告,所有内容像被扒光了衣服一样赤裸裸地展示着。后来才发现,问题出在标签里那个不起眼的xmlns属性上。
xmlns全称XML Namespace,是XHTML区别于普通HTML的关键标识。当浏览器看到xmlns="http://www.w3.org/1999/xhtml"时,它会说:"啊,这是个XHTML文档,我要用处理网页的方式渲染它"。但如果写成了xmlns="http://www.w3.org/1999/en",浏览器就会困惑:"这好像是某种XML,但我不知道具体规则,就按纯XML显示吧"。
这种错误特别容易发生在从HTML转向XHTML的开发者身上。我们可能觉得"en"代表英文,顺手就写进去了。实际上,W3C为XHTML专门保留的命名空间URI是固定不变的"http://www.w3.org/1999/xhtml",任何其他值都会触发浏览器的XML解析模式。
XML命名空间本质上是个"防重名系统"。想象你参加国际会议,主持人说"请王先生发言"——如果现场有多个王先生就会混乱。这时就需要用"北京代表团的王先生"来精确指定。xmlns就是这个"代表团声明",它告诉处理器标签属于哪个规范体系。
在XHTML中,正确的命名空间声明相当于说:"这里所有标签都遵循W3C 1999年定义的XHTML规范"。浏览器听到这个声明后,就会调用内置的XHTML渲染引擎。而错误的命名空间就像说错了代表团名称,浏览器找不到对应的处理规则,只能按最基础的XML方式显示。
当命名空间错误时,浏览器会经历这样的判断过程:
这种降级处理是XML的设计特性。XML本身只是数据格式,不像HTML有预设的呈现方式。当浏览器无法确认文档类型时,最安全的做法就是保持数据原貌。
遇到以下情况时,应该首先怀疑命名空间问题:
除了肉眼检查代码,还可以用这些工具辅助诊断:
bash复制xmllint --noout yourfile.xhtml
这个命令会报告XML格式错误对于文章开头的错误案例,修复很简单:将
html复制<html xmlns="http://www.w3.org/1999/en">
改为
html复制<html xmlns="http://www.w3.org/1999/xhtml">
但完整的XHTML文档还需要注意这些配套设置:
apache复制AddType application/xhtml+xml .xhtml
html复制<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
对于需要兼容新旧浏览器的项目,可以采用内容协商策略。在Apache服务器中可以这样配置:
apache复制<Files *.xhtml>
ForceType application/xhtml+xml
Header set Vary "Accept"
</Files>
同时在前端加入兼容性检测:
javascript复制if (!document.implementation.hasFeature(
"http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")) {
// 处理不支持XHTML的浏览器
}
除了案例中的"en"错误,我还见过这些错误写法:
http://www.w3.org/2002/xhtml (未来版本提案,未正式使用)http://www.w3.org/TR/xhtml1 (规范文档URL,不是命名空间)http://www.w3.org/XHTML (大小写错误)在XHTML中链接CSS需要特别注意:
html复制<!-- 正确写法 -->
<?xml-stylesheet href="style.css" type="text/css"?>
<link rel="stylesheet" href="style.css" type="text/css" />
<!-- 可能失效的写法 -->
<style>
/* 直接写CSS可能需要CDATA包裹 */
<![CDATA[
body { color: red; }
]]>
</style>
XHTML对编码声明更加严格,建议采用完整形式:
html复制<?xml version="1.0" encoding="UTF-8"?>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
我在实际项目中遇到过因BOM头导致解析失败的情况。现在都会用高级编辑器确保文件以无BOM的UTF-8格式保存。