Friday, October 24, 2008

挑战 XHTML 的 Strict 标准

我的 Blog 网页在 Doctype 声明上一直使用的是 XHTML 的 Strict 标准,当初在模板制作完成时是校验过的,可是随着后来无数次的修改、内容添加,现在已经不能通过 W3C 的语法校验了,加上 Google Blogger 在发布页面的时候似乎也并没有考虑目标模板的 Doctype 标准,也部分导致校验的失败。

经过一个下午的努力,终于基本上解决了所有 XHTML 的语法问题,总结如下。
<a> 标签没有 target 属性
在 Strict DTD 里面,超链接 <a> 标签 没有 target 属性,因此不能利用 target="_blank" 这样的代码来达到新开页面打开链接的目的。为了实现同样的功能,通常的办法是用 rel="external" 来替代 target="_blank",然后用如下 JavaScript 代码来处理链接:
function externalLinks() {
var linkArray = document.getElementsByTagName('a');
for (var i = 0; i < linkArray.length; i++) {
var link = linkArray[i];
if (link.getAttribute('rel') == 'external') {
link.target = '_blank';
}
}
}
然后将该 externalLinks() 函数添加到页面的 onLoad 事件中。如:
<body onload="externalLinks();">
<img> 标签必须添加 alt 属性
对于 <img> 标签来讲,alt 属性是必须的。给图片添加 alt,一方面当图片因为各种原因无法显示的时候,能给访问者以提示;另一方面也便于搜索引擎判断图片的内容,以及更准确的建立索引。
<img> 标签没有 border 属性
<img> 标签是没有 border 这个属性的。我们通常会加上 border="0",主要是因为把图片放在链接标签 <a> 里时,浏览器会加上一个链接默认颜色的边框,而这通常是多余的。在 Strict 标准中,不能用 border 属性来去掉边框,而只能使用 CSS 控制。同样 align 属性也是不存在的,要实现 absmiddle 这样的目的,也只能用 CSS 代替。
<blockquote> 标签内必须使用 block 级别的标签
<blockquote> 标签用来在页面上表示引用的内容,例如,最常见的,引用代码。我通常习惯将代码的内容放在 <code> 标签中,而这个标签是 inline 级的,不符合 Strict DTD 的要求。<strong>、<b> 等同样会导致问题。符合要求的 block 级标签包括:<address>, <blockquote>, <del>, <div>, <dl>, <fieldset>, <form>, <h>, <h2>, <h4>, <h5>, <h6>, <hr>, <ins>, <noscript>, <ol>, <p>, <pre>, <script>, <table>, <ul>。
不能使用 <embed> 标签
这个问题最容易出现在引用外部媒体文件时,例如 MP3 音乐、视频等。很多资料推荐同时使用 <object> 和 <embed> 来增强媒体引用元素的浏览器兼容性,但是很不幸的,Strict DTD 并未定义 <embed>。其实我们完全可以不使用 <embed> 一样能够兼容浏览器。例如 Youtube 给的代码一般是这样的:
<object width="425" height="344">
<param name="movie"
value="http://www.youtube.com/v/uhsjNTEJD3c"></param>
<param name="allowFullScreen" value="true"></param>
<embed src="http://www.youtube.com/v/uhsjNTEJD3c"
type="application/x-shockwave-flash"
allowfullscreen="true"
width="425" height="344"></embed>
</object>
这样无法通过校验。我们可以改成:
<object type="application/x-shockwave-flash"
width="425" height="344">
<param name="movie"
value="http://www.youtube.com/v/uhsjNTEJD3c"/>
<param name="allowFullScreen" value="true"/>
</object>
实体用法问题
在 XML 中,实体的写法是 &entity;,以一个 & 符号开头,一个分号结束。因此,Strict 标准的 XHTML 里面不允许出现任何单独的 & 符号,即使是在 URL 中用来分隔查询参数。需要用到这个符号的时候,要用 &amp; 来表示。通常一个实体用法的错误会同时导致 5 个校验时的错误,当解决以后,这 5 个错误会同时消失。由于 Blogger 在发布页面时 URL 直接使用了 & 符号,因此会直接导致 Strict 标准的 XHTML 校验失败。
重复的 id 值
对于 XHTML 标签来讲,id 属性的值必须唯一,如果一个文档中出项重复的 id 就会导致问题。出现这种问题,通常是把 id 属性放在了 Blogger 模板会循环输出的部分。
另外,Blogger 提供的模板中,backlinks 那一部分会导致 4 个不同类别的问题。凭心而论,Blogger 模板在 backlinks 这一块的代码实在写的很烂,用了三个不同的 js 文件,用 JavaScript 输出 CSS,不但使得不同模板之间难以更改这一部分显示的样式,也导致了很多 XHTML 的语法校验问题。例如 Blogger 自己的 Buzz,打开任一个文章的独立页面的源代码,Doctype 声明赫然是 XHTML 1.0 Strict,然而 backlink 那一块的代码不用校验也能看出漏洞百出。

Blogger 目前版本的网站出自著名设计师 Douglas Bowman 之手,其本人对 XHTML 以及 CSS 有着非常深刻的研究。在设计之初,Blogger 还没有 Backlinks 的功能,显然这个蹩脚的 Backlinks 是后来由其他人加上去的。不知道 Bowman 先生在看到这一幕后会做何感想。

Google 黑板报用的是同样的 backlink 代码,不过比 Buzz 知趣的是它的模板干脆去掉了 Doctype 声明。只不过作为 Google 旗下的网站,页面连 Doctype 声明都没有,也是一件汗颜的事情。

言归正传,以下列出 backlink 这部分代码导致的问题以及解决方法。
<div> 和 <dl> 之间的嵌套问题
在 Blogger 给出的默认模板代码中,是用 <dl> 来实现反向链接列表的;可问题在于,他们将 <BlogItemBacklinks> 放在了 <dl> 之内,而在生成页面时,会将 <BlogItemBacklinks> 这一对模板标签替换成一对 <div> 标签,从而导致 <div> 被嵌套在 <dl> 内。在 Strict DTD 里,<dl> 标签内只允许出现 <dt> 和 <dd> 两个子标签。解决办法是把 <BlogItemBacklinks> 放到 <dl> 外面,当然这样虽然让 XHTML 语法通过校验,但实际的运行结果,会导致每个反向链接条目会占用一个 <dl> 块,而不是预期的放在循环的若干个 <dt> 和 <dd> 中。通过 CSS 可以解决条目之间间距的问题。如果要完美解决这个问题的话,就只有自己重写 Blogger 提供的 JavaScript 函数来改变这一行为了。
<script> 标签的 defer 属性
在 Blogger 用模板生成页面时,除了将 <BlogItemBacklinks> 替换成一对 <div> 以外,还会在开标签的 <div> 之前加上一个 <script;> 用来引入相关的 JavaScript,同时给出了一个 defer="true" 属性,然而,根据 Strict DTD,defer 属性只能有一个值,只能是 defer="defer"。
<noscript> 内只能用 block 级别标签
在生成以上 <script> 标签的同时,Blogger 给出了一个 <noscript>,用来当浏览器不支持脚本的时候显示一个 Blog Search 的链接。可是 <noscript> 标签内只能用 block 级别的标签,直接用 <a> 这样的 inline 标签是不行的。
模板占位符问题
在模板中这段关于 backlink 的代码中,Blogger 用了一些模板标签作为占位符。通常模板标签会在生成具体网页时替换掉,但这里的占位符不会,它们要在实际生成 backlink 条目时被 JavaScript 程序换掉。但是在做 XHTML 语法校验时,这些占位符以 HTML 标签的形式存在于代码中,而又显然不属于 XHTML 定义的范围,从而导致校验失败。解决办法是将它们的尖括号转移,写成诸如 &lt;$BlogBacklinkTitle$&gt; 的形式,这样既能够被 JavaScript 成功识别,保证功能正常,又能通过 Strict 语法校验。要特别注意,其中 <$BlogBacklinkDeleteIcon$> 不要转义,这个模板标签是在页面生成时被替换的,而不是 JavaScript 的数据占位符。
最后,Google 黑板报最近也发布了一篇关于互联网标准性的文章,这篇文章也提供了很多关于改进网站 HTML 代码的参考信息。