JunChen注:omemo.net網站似乎已經掛掉,鏈接都失效了。文章寫得非常不錯,一直是Best of 456 Berea Street。在這裡發布的時候我進行了少量代碼上和翻譯上的修改,以忠實原著。
我使用XHTML有些年了,但直至去年夏天我才著眼於如何正確使用,那就是說,以application/xhtml+xml的MIME類型來伺服(server)它。雖然我遇到了這些問題,但我知道問題遠非如此。就如你即將發現的一樣,當你開始使用真正的XHTML,你會遭遇很多似乎細小但讓人困惑的問題。
請注意這不是一篇討論支持或反對使用XHTML的文章。我只是寫下我所知道的潛在的易犯錯誤,並且讓你自己來決定自己的選擇:HTML 4.01,為所有浏覽器伺服為text/html的XHTML 1.0或者為能夠處理其的浏覽器伺服為application/xhtml+xml而其他浏覽器則伺服為text/html的XHTML 1.0。否則有些東西會完全不一樣。
只有在問題發生的時候,我才有機會去了解和認識這些東西。有些情況下我必須花很多時間來查找問題和求助於其他人,來尋求一個解決方案。但我在其中學到不少東西,我會把我已經使用XHTML後應該知道的都告訴你。
注意我這裡提及的問題只會發生在能正確處理application/xhtml+xml MIME類型的用戶代理中,而因此XHTML被作為XML。這也可能是這裡不提及XHTML的早期使用的原因——很少有人使用這樣的浏覽器,所以幾乎不會有人因只伺服為text/html的XHTML所煩憂。
今天,實際上把XHTML伺服為application/xhtml+xml正慢慢變得平常。我所知道的理由有兩個:
使用Firefox,Mozilla,Opera,Safari和其他兼容XHTML浏覽器的人數增加了很多,所以你不再僅僅為自己和伙伴這樣做。嗯。或許你就這樣做,當將影響更多人。
在web開發者之間,對XHTML的真正面目是什麼的覺醒越來越多了。使用XHTML已經有多次多時的熱烈的討論,尤其是伺服為text/html的時候。如果你參與了任何一次討論,你知道我在說什麼。
假如你,像我,決定實現某些類型的content negotiation和在傳送XHTML的時候使用正確的媒體類型,你需要知道什麼能(和將)在你發布的文檔中發生,並且知道怎樣避免問題的發生。對於對content negotiation同進行content negotiation的腳本例子有興趣的讀者,我推薦你閱讀Content Negotiation和Serving up XHTML with the correct MIME type。還有很多這種類型的文章,但這是我讀到的最精彩的兩篇。
每一個基本的教程都有一些HTML和XHTML的明顯區別:元素和屬性名字使用小寫,屬性值總要用引號。不要使用簡化屬性,確保所有的元素都有結束標簽和沒有不正確的嵌套等等。但是,當XHTML伺服為application/xhtml+xml時還需要知道更多東西。
良好的結構是必須的
文檔必須是良好的結構(well-formed)的XML(跟合法的(valid)XHTML不必然相同)。就是必須,不是可能。
如果文檔結構不好,符合標准的浏覽器(當前我知道Mozilla,Firefox,Netscape,Camino,Opera,Safari和OmniWeb——相當多的浏覽器除了IE)將會顯示錯誤信息並且以某種方式中止處理文檔。
此外,這還意味著不再使用未編碼的"&"號。
XML聲明可能是必須的
如果要使用UTF-8或者UTF-16以外的變法,必須要XML聲明,除非HTTP頭已經提供編碼。
在HTTP頭中是否要指定字符編碼有些模糊,Architecture of the World Wide Web, Volume One: Media Types for XML這樣寫的:總體上,不應該在協議頭為XML數據指定字符編碼,因為數據本身已描述。
另一方面,XHTML 1.0, Second Edition: Character Encoding寫到:
為了讓文檔使用指定的字符編碼,最好的辦法是保證web服務器發送正確的頭。
就是說,在XML聲明中指定字符編碼是好的習慣:
<?xml version="1.0" encoding="iso-8859-1"?>
只有五個實體是安全的
只有五個預定義的實體(<, >, &, ", 和')的支持是有保證的。其他的可能完全被忽略或者直接輸出。比如,如果XHTML文檔包含如 或者”的實體,Safari會直接地輸出。Opera反而選擇忽略未知的實體,同時Mozila家族會認得這些實體並且就像HTML中“如果文檔引用公共的映射浏覽器偽DTD目錄中的標識符並且沒有單獨聲明的文檔”來處理。
使用UTF-8字符編碼是最受推薦的,讓你(幾乎)可以使用你需要鍵入文檔的任意字符,不需要實體或者字符編號。如果你不能或不願使用UTF-8,數字式的字符編號是可以支持和安全使用的。
SGML式注釋的內容可能會被忽略
SGML注釋(HTML風格注釋, <!-- 注釋 -->)可能會(並且會)被浏覽器當作注釋,就算是在script或者style元素內部使用。
在HTML中,普遍地把script和style的內容裝入注釋中,為的是在不認識script或style元素的浏覽器中隱藏他們,並且在頁面上把其內容生成平白文本。
在XHTML中,這樣做會引起浏覽器忽略掉注釋裡的任何內容。
在老的浏覽器中隱藏script和style的習慣可以追溯到1990年代中期。我的經驗是,有如此表現的浏覽器是十分罕見的,所以你可以安全地忽略它們,並且停止在腳本和樣式中裝入SGML式注釋,就算你使用的是HTML。
腳本和樣式元素的內容也被當作XML
樣式和腳本元素是PCDATA(parsed character data,解析字符數據)塊,不是CDATA(character data,字符數據)塊。因此,在其內看起來像XML的任何東西都會被當作XML來解析,並且會引發錯誤除非是良構的。
為了在script或style塊中使用<、&或者--,你需要用CDATA :
<script type="text/javascript">
<![CDATA[
...
]]>
</script>
在CDATA裡,你可以任何順序的字符,它們不會被當作XML來解析(除了結束CDATA部分]]>)。
需要以text/html發送的文檔中,CDATA部分的起始和結束標簽需要注釋掉,以便在不能處理CDATA部分的浏覽器中隱藏:
<script type="text/javascript">
// <![CDATA[
...
// ]]>
</script>
<style type="text/css">
/* <![CDATA[ */
...
/* ]]> */
</style>
如果要確保很老的浏覽器隱藏CDATA部分,需要使用更為復雜的方法,像在Ian Hickson的Sending XHTML as text/html Considered Harmful中描述的那樣:
<script type="text/javascript">
<!--//--><![CDATA[//><!--
...
//--><!]]>
</script>
<style type="text/css">
<!--/*--><![CDATA[/*><!--*/
...
/*]]>*/-->
</style>
一個更好的辦法可能是在發送text/html的文檔前使用content negotiation腳本來刪除任何CDATA部分。
當然,最聰明和安全的途徑是把所有的CSS和JavaScript都移動到外部文件中,但不總是現實的做法。
沒有會自動補全的元素
在HTML中,假如表格的tbody元素漏寫的話浏覽器會自動補全,而XHTML不會。如果你沒有清楚地添加tbody,它就不會出現。在編寫CSS選擇器和JavaScript的時候請銘記在心。
用document.write編寫的腳本不再工作
在XHTML中使用JavaScript,document.write不會工作。Ian Hickson在Why document.write() doesn’t work in XML解釋了原因。你需要使用document.createElementNS()代替。關於更多可以在Experts Exchange中的論壇主題中找到。
這也是Google AdSense不在XHTML中工作的原因之一。那些希望以application/xhtml+xml伺服XHTML並且使用Google廣告的人,這兒有一個解決辦法:Simon Jessey的Making AdSense work with XHTML。盡管有點麻煩,但還是工作了(我在這裡也使用了),同時被Google所認可。
引入樣式元素
在XHTML中,為了兼容定義CSS規則的XML方法,你應該使用XML樣式表聲明(訪問 XHTML 1.0, Second Edition: Referencing Style Elements when serving as XML的XML樣式表聲明和Associating Style Sheets with XML documents的xml-stylesheet處理說明)。要載入外部CSS文件,我們需要使用style元素,同時應該使用XML樣式表聲明來引入樣式元素。為此,使用id屬性給style元素一個分解的標識符,然後在XML樣式表聲明中引入該標識符:
<?xml-stylesheet href=”stylesheet1.css” type=”text/css”?>
<?xml-stylesheet href=”#stylesheet2” type=”text/css”?>
<!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=”en”
lang=”en”>
<head>
<title>XML stylesheet declaration</title>
<style type=”text/css” id=”stylesheet2”>
@import “stylesheet2.css”;
</style>
</head>
我不知道在實際中究竟有多必