優化HTML

爲何要保持標籤整潔

客戶端的優化近來倍受關注,可是有些較基本的方面卻被忽視。如果你仔細觀察某些頁面(即便是那些本來應該深度優化的頁面),很容易就能在他們的標籤中找到一大堆冗餘的、不高效的結構。所有這些累贅給本來應該儘可能保持輕量級的頁面增加了不必要的負擔。

保持文檔整潔的原因不一定是爲了更快的加載速度,更是爲了讓我們的建築能有一個結實而牢固的基礎,整潔的標記意味着更好的可訪問性,更方便的維護,更易被搜索引擎檢索,更小的體積僅僅是保持文檔整潔的一個附加屬性,也是我們應該這樣做的另一個理由。

這篇文章裏面,我們來瞧瞧html該如何優化:去掉一些不好的標記習慣、通過刪除冗餘的結構來減小文檔體積,並應用壓縮技術,我們來瞧瞧現有的壓縮工具,並分析他們做得好和做得不好的地方,我們也會探討一下在將來可以怎麼做。

一團糟的寫法

來看看有哪些最容易犯的錯誤

1.在script標籤內放html註釋

當今一個最嚴重的冗餘代碼是在script標籤內放置HTML註釋——<!-- -->,這裏不需要說得太多,一句話足夠:需要通過這種方式來阻止錯誤的瀏覽器(例如‘95 Netscape 1.0)幾乎滅絕了,腳本內的註釋是完全不必要的累贅,應該被毫不留情地刪除掉。

2.<![CDATA[ … ]>

另外一種常見但是不必要的阻止錯誤的方式是將CDATA塊放到script標籤內:

<script type="text/javascript">
   
//<![CDATA[
     
...
   
//]]>
</script>

這個神聖的目標不切實際。儘管CDATA塊是一個阻止XML解析器將<&當成標籤的開頭的一個很好的方式,但是只有在真正的XHTML文檔(被當成“application/xhtml+xml” content-type來處理的文檔)內纔有效。目前大部分的網頁仍然被當成“text/html”來處理的(因爲,舉個例子,IE目前仍然不支持 XHTML),所以他們都被當成HTML來解析,而不是XML。

除非你已經把文檔當成"application/xhtml+xml"來處理,否則幾乎沒有任何理由把CDATA塊放在裏面,即便你打算以後使用XHTML,也有必要先把這些不必要的東西去除,等到真正需要的時候再加進來。

當然,一個終極的解決方案是完全避免使用內聯的script標籤(爲了利用外部script的緩存機制)。

3.類似οnclick="…", οnmοuseοver=""這些

html事件屬性有一些合理的應用場景,比如爲了性能上的考慮或者爲了應付古老的瀏覽器(儘管我還沒有發現只支持html事件屬性註冊方式——οnclick="..."而不支持dom節點屬性註冊方式element.onclick = ...的情況)。除了一些衆所周知的拒絕它們的理由如行爲和內容的分離或者便於重用,它還會污染html標記。把事件邏輯轉移到外部的腳本里面,我們可以充分利用腳本的緩存機制。事件處理邏輯不必在每次的頁面請求中都被傳送到客戶端。

4.οnclick="javascript:…"

javascript 中一個很有趣的怪現象:javascript:僞協議和html事件屬性處理器混合成了這樣一個怪胎(發生的機率高達106,000 (!)),事實上html屬性上的事件處理器會整體變成一個函數體,然後這個函數變成一個事件處理程序(通常,會先把函數的作用域加強來包含元素本身和它的部分或全部的父級)。“javascript:” 這部分變成了一個不必要的標籤並且幾乎沒有任何作用。

5. href="javascript:void(0)"

繼續javascript僞協議,有一個很著名的代碼片段:href=”javascript:void(0)”,他的作用是阻止鏈接的默認行爲。當javascript被禁用、不可用或出錯的時候這個糟糕的寫法使得鏈接完全不可訪問。毫無疑問最理想的處理方法是將合適的url寫入href裏面,然後通過事件處理器來阻止鏈接的默認行爲。另一種情況,如果鏈接是動態創建之後插入到頁面中(或者最初是隱藏的,然後才通過 javascript讓其顯示),使用href=”#”比用javascript:更整潔,更快速。

6.style="…"

使用style屬性並沒有什麼太嚴重的錯誤,只是如果把它裏面的內容轉移到一個外部的樣式表裏面,我們就能利用到源代碼的緩存機制。這跟前面提到過的 html屬性事件處理器類似。即便你只是爲了給一個特定的元素設定樣式並且沒有打算重用它們,這些樣式信息會在每次頁面被請求的時候都傳送一次。把樣式轉移到外部樣式表裏面能防止這個,因爲外部樣式表傳送一次之後會緩存到客戶端。

7.<script language=”Javascript” … >

也許一個最搞不懂的屬性就是script標籤的language屬性,這個古老的屬性早在1999年、10年前官方推薦HTML 4.01標準的時候就被拋棄了,除非在必須指定javascript版本(這個也不太可靠,應該儘可能避免)這種極少的情況下,否則沒有任何理由繼續使用這個屬性。

8.<script charset=”…” … >

另一個搞不懂的屬性是script的charset屬性,有時候我會見到下面這種結構:

<script type="text/javascript" charset="UTF-8">
   
...
</script>

這裏要說的是charset屬性只放在“外部”script標籤(有寫src 屬性的script標籤)上纔有意義。HTML 4.01 甚至說:

注意charset屬性指定了src屬性所指定的腳本的字符編碼;它不關心script標籤的內容。

測試表明瀏覽器都遵循了這條標準。

搜索一下這個結構,出現了2000次。當你發現像Textmate這些流行的編輯器裏面都錯誤地使用了charset之後就一點都不覺得奇怪了。

9. 附加的優化方法

剛纔我們說到了一些應該避免的不好的寫法,但是還有一些,那就是刪除冗餘的部分。下面提到的一些優化是有些爭議的,因爲他們主要出於體積上的考慮。所以我把它們放在這裏不是作爲建議,而是作爲一種選擇。請各位三思而行。

1. <style media=”all” …>

HTML 4.01定義了style上的media屬性,用來指定特定的媒介——屏幕、打印機、手持設備等等。media的一個可能的值是all,這個值恰好是現代瀏覽器的默認值,如果你發現自己在使用media="all",那麼你可以省去它,讓瀏覽器自動幫你設置

有趣的是,HTML 4.01說media的默認值是"screen"。但是我測試的每一款瀏覽器都沒有按照這條標準來執行,而把默認值設定成了"all"。這可能就是爲什麼HTML5草案把默認值指定爲"all",來和瀏覽器的行爲達成一致。

2.<form method=”get” …>

另一個默認值——GET——form 的"method"屬性常常是被明確設定的。其實除了不夠清晰,省去它沒有其他壞處。注意HTML 5草案沒有更改這個行爲

3. <input type=”text” …>

INPUT元素的type屬性默認值爲"text"——在HTML 4.01HTML 5草案裏面都是如此。去掉這個屬性對有很多文本輸入框的頁面來說能減少很大一部分體積。

4.<meta http-equiv=”Content-type” …>

指定頁面的字符編碼總是給人很大的困惑。和我們想當然的相反,META元素上指定的Content-type沒有 HTTP頭裏面指定的“Content-type”的優先級高。當二者(HTTP頭和META元素)都被設定的情況下,HTTP頭優先。

如果你能控制服務器返回並且能夠正確地設定HTTP頭的Content-type,那麼省略META標籤也是可以的。保留它的唯一原因是爲離線瀏覽該頁面的時候指定編碼。

5.<a id=”…” name=”…” …>

把”name”屬性和”id”屬性一起使用的主要原因是爲了兼容古老的瀏覽器(如Netscape 4)。他們不能鏈接到用“id”指定的錨點,所以必須設置”name”,如果你的頁面有有元素既設置了”id”又設置了”name”,並且不在意這些古老的瀏覽器,那麼你可以擺脫這個古老的寫法了。

注意一些副作用。如果你在腳本中通過name來查詢元素(document.getElementsByNamedocument.evaluatedocument.querySelectorAll等等)把name替換成id可能會把事情搞砸。還要記住document.anchors只返回帶有name屬性的元素

6.<!doctype html>

一年多以前,Dustin Diaz建議使用HTML 5文檔類型,作爲減少頁面體積的一個途徑。這不是一個重要的優化方式,但是如果你不在乎是否通過檢驗並且需要使頁面儘可能小巧,使用<!doctype html>是一個可行的備選方案。測試表明這個奇特的文檔聲明可以觸發大量的瀏覽器的標準模式。

激進的優化方法

如果你渴望更多的,這裏還有一些比較極端的方法。有一些(如略去選填的標籤)已經出現過一段時間了,還有些之前沒出現過。儘管這些做法看起來有些唐突,但是它們都可以通過檢驗,如果你的頁面是HTML的而不是XHTML的。但是你的頁面是HTML的,不是嗎?;)

  1. 去掉HTML註釋
  2. 去掉/減少空格
  3. 省去選填的結束標籤(<p> → <p>foo)
  4. 如果允許,去掉屬性值的引號 (<p class="foo"> → <p class=foo>)
  5. 刪除布爾類型的屬性的選填值(<option selected="selected"> → <option selected>)
  6. 轉移內聯樣式、內聯腳本、和html事件屬性 (如果不能刪掉它們的話)
  7. 轉移class和id(需要同步修改腳本和樣式)
  8. 把URL的協議名稱去掉 (http://example.com → //example.com)

但我們可以壓縮

當頁面壓縮之後這些優化還有意義嗎?難道gzip不是已經把這些冗餘的標記都搞定了嗎?畢竟,我們說的是一個文本格式的東西。

用處還是有的!

首先,必須清楚不是每個人都能gzip,這是很悲哀的事情,但好的一面是在這種情況下HTML 優化的意義就更大了。

其次,即便頁面壓縮了,我們還可以節省5-10kb(平均每個頁面)。在比較大的頁面中還可以節省得更多。儘管看上去也沒有太多,但實際上每一個字節都很重要

作爲一個壓縮大型頁面的例子,我優化了一下非官方的ECMA-262, 第三版規範的HTML版本,這個頁面最初爲750KB(gzip之後爲131KB),優化之後爲606KB(gzip之後115KB)。也就是說gzip之後節省了16KB,僅僅是去掉空格、註釋、屬性值的引號、選填標籤。你可以看看這個壓縮後的版本和以前的版本看起來是一模一樣的。

最後,像去除空格和註釋這樣的優化能使得文檔樹更輕量,潛在地增強了頁面的渲染效率。

物極必反

像其他一些優化一樣,我們很容易矯枉過正。HTML Compact 就是HTML壓縮工具裏面做得太過的一個例子,這個優秀的windows程序用了一種很“獨特”的方式來壓縮HTML——用javascript把內容寫入到頁面中。

把這個完美的頁面:

<html>
<head>
   
<title></title>
</head>
<body>
   
<div>
   
<ul>
       
<li>foo</li><li>bar</li><li>baz</li>
       
<!-- few more dozens of list elements ... -->
   
</ul>
   
</div>
</body>
</html>

變成這副模樣:

<!--hcpage status="compressed"-->
<html>
<head>
 
<SCRIPT LANGUAGE="JavaScript" SRC="hc_decoder.js"></SCRIPT>
 
<title></title>
</head>
<BODY>
 
<NOSCRIPT>To display this page you need a browser with JavaScript support.</NOSCRIPT>
 
<SCRIPT LANGUAGE="JavaScript">
   
<!--
      hc_d0
("Mv#d|\x3C:,&c@w4YFAtD1 [... and so on, another couple hundreds of characters ...]");
   
//-->
 
</SCRIPT>
</BODY>
</html>

不用說,像這樣的“優化”永遠不應該在網絡上出現,除非你的目的是降低頁面對用戶和搜索引擎的可訪問性。並且裏面的NOSCRIPT標籤也讓人很不爽,這種東西對某些能阻止javascript的防火牆來說也是不起作用的。餿主意,壞做法!

上面是一個很好的反例,但是還有一些也是應該注意的:

反面教材

1. 去除文檔聲明

HTML Compresor裏面有一個選項——默認是開啓的——去除文檔聲明。我實在想不出這麼做會有什麼的好處,相反,沒有文檔類型會激活怪異模式,使頁面的佈局和行爲都出現很嚴重的問題。文檔類型要麼放着不動,要麼被替換爲一個更簡短的——HTML5聲明。

2.把STRONG用B替代,EM用I替代

還是那個HTML壓縮工具裏面有一個有害的選項是把元素用比他們更短的“替代品”來替換。問題是B不是STRONG的替代品。I也不是EM的替代品。 STRONG和EM是有語義的——表示強調,而B和I只是去改變字體樣式的;他們能改變文字的展現,但是沒有任何語義。

雖然瀏覽器把他們顯示成一樣的,但是屏幕閱讀器和搜索引擎知道他們的區別。

3.去除title,alt屬性和label元素。

一條比較重要的原則是如果優化會損失可訪問性就不要優化。你可能很想刪掉IMG上的“alt”屬性,或者鏈接上的“title”屬性,但是節省少量的字節相對於損失的可訪問性來說的確是得不償失。


發佈了12 篇原創文章 · 獲贊 1 · 訪問量 2529
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章