Web前端瀏覽器相容初探

葉小釵發表於2013-04-23

  前言

  瀏覽器相容是前端開發人員必須掌握的一個技能,但是初入前端的同學或者其他後臺web開發同學往往容易選擇忽略,而形成兩個極端:

  1 我最開始都是使用IE6,IE6上沒問題,其它瀏覽器坑爹(多出現與前端後端一起搞的同學,小生2年前就這種狀態,鼓勵人家用ie6.。。。)

  2 我要遵循標準,我只要ff就好,IE就是坑爹的玩意,我不必去理他(小生一年前的心態。。。)

  現在看來,之前的想法都是不對的,我們誠然應該追求最新的瀏覽器使用最新的技術,但是漸進增強,向後相容的思想一定要有,

  因為就現在IE6在中國的份額也是不容小視的。

  拋開之前的大道理,我們說點實際的問題,哪次前端面試不問相容性問題?哪次我們又能回答的很好?反正我就沒一次說好的,知不足然後能改,

  我前端時間便經過整理形成這篇文章,文章有很多不足,希望各位指正、補充,後面若是能形成一篇較全面的前端相容文章就善莫大焉了!

  為什麼會有相容問題?

  由於市場上瀏覽器種類眾多,而不同瀏覽器其核心亦不盡相同,所以各個瀏覽器對網頁的解析就有一定出入,這也是導致瀏覽器相容問題出現的主要原因,我們的網頁需要在主流瀏覽器上正常執行,就需要做好瀏覽器相容。

  使用Trident核心的瀏覽器:IE、Maxthon、TT;

  使用Gecko核心的瀏覽器:Netcape6及以上版本、FireFox;

  使用Presto核心的瀏覽器:Opera7及以上版本;

  使用Webkit核心的瀏覽器:Safari、Chrome。

  而我現在所說的相容性問題,主要是說IE與幾個主流瀏覽器如firefox,google等。

  而對IE瀏覽器來說,IE7又是個跨度,因為之前的版本更新甚慢,bug甚多。從IE8開始,IE瀏覽器漸漸遵循標準,到IE9後由於大家都一致認為標準很重要,可以說在相容性上比較好了,但是在中國來說,由於xp的佔有率問題,使用IE7以下的使用者仍然很多,所以我們不得不考慮低版本瀏覽器的相容。

  對瀏覽器相容問題,我一般是這樣分類的,HTML,Javascript相容,CSS相容。 其中html相關問題比較容易處理,無非是高版本瀏覽器用了低版本瀏覽器無法識別的元素,導致其不能解析,所以平時注意一點就是。特別是HTML5增加了許多新標籤,低版本瀏覽器有點影響時代進步啊;

  javascript相容性問題

  在javascript中,各個瀏覽器基本語法差距不大,其相容問題主要出現在各個瀏覽器的實現上,尤其對事件的支援有很大問題,在此我就說說我知道的幾個問題。

  ① 在標準的事件繫結中繫結事件的方法函式為 addEventListener,而IE使用的是attachEvent

  ② 標準瀏覽器採用事件捕獲的方式對應IE的事件冒泡機制(即標準由最外元素至最內元素或者IE由最內元素到最外元素)最後標準方亦覺得IE這方面的比較合理,所以便將事件冒泡納入了標準,這也是addEventListener第三個引數的由來,而且事件冒泡作為了預設值。

  ③ 事件處理中非常有用的event屬性獲得亦不相同,標準瀏覽器是作為引數帶人,而ie是window.event方式獲得,獲得目標元素ie為e.srcElement 標準瀏覽器為e.target

  ④ 然後在ie中是不能操作tr的innerHtml的

  ⑤ 然後ie日期函式處理與其它瀏覽器不大一致,比如: var year= new Date().getYear(); 在IE中會獲得當前年,但是在firefox中則會獲得當前年與1900的差值。

  ⑥  獲得DOM節點的方法有所差異,其獲得子節點方法不一致。

  IE:parentElement parentElement.children Firefox:parentNode parentNode.childNodes childNodes的下標的含義在IE和Firefox中不同,Firefox使用DOM規範,childNodes中會插入空白文字節點。一般可以通過node.getElementsByTagName()來回避這個問題。

  當html中節點缺失時,IE和Firefox對parentNode的解釋不同。例如:

  <form>  <table>   <input/>  </table> </form> IE:input.parentNode的值為空節點 Firefox:input.parentNode的值為form 解決方法:Firefox中節點沒有removeNode方法,必須使用如下方法 node.parentNode.removeChild(node)

  ⑦ 關於AJAX的實現上亦有所不同;

  就javascript來說,各大瀏覽器之間的差異還是不少的,但是具體我變得這裡都不大關注了,因為我們開發過程中一般都會使用類庫,若是不使用,都會自己積累形成一個類庫,所以就js而言,相容性問題基本解決了。

  讓人頭疼的CSS相容

  因為之前對css的理解不夠深入,也沒有經過系統的學習,所以一度認為css是前端最難的東西,但真的學習後,才發現css真的很難。。。有很多東西啊!!!

  我覺得最讓人頭疼的問題還是CSS問題,因為一點點佈局上的bug,可能導致整個頁面的錯位,在使用者看來這是極不專業的。

  現在我就簡要說說我對CSS相容問題的認識: 先說點Hack的知識(真正的高手是不用Hack的,但要成為高手必須通過Hack這一關)

/* CSS屬性級Hack */ 

color:red; /* 所有瀏覽器可識別*/ 

_color:red; /* 僅IE6 識別 */ 

*color:red; /* IE6、IE7 識別 */ 

+color:red; /* IE6、IE7 識別 */ 

*+color:red; /* IE6、IE7 識別 */ 

[color:red; /* IE6、IE7 識別 */ 

color:red\9; /* IE6、IE7、IE8、IE9 識別 */ 

color:red\0; /* IE8、IE9 識別*/ 

color:red\9\0; /* 僅IE9識別 */ 

color:red \0; /* 僅IE9識別 */ 

color:red!important; /* IE6 不識別!important 有危險*/

/* CSS選擇符級Hack */ 

*html #demo { color:red;} /* 僅IE6 識別 */ 

*+html #demo { color:red;} /* 僅IE7 識別 */ 

body:nth-of-type(1) #demo { color:red;} /* IE9+、FF3.5+、Chrome、Safari、Opera 可以識別 */ 

head:first-child+body #demo { color:red; } /* IE7+、FF、Chrome、Safari、Opera 可以識別 */ 

:root #demo { color:red\9; } : /* 僅IE9識別 */

/* IE條件註釋Hack */ 

<!--[if IE 6]>此處內容只有IE6.0可見<![endif]--> 

<!--[if IE 7]>此處內容只有IE7.0可見<![endif]-->

  接下來說說一些我知道的BUG:

  ① css盒模型在IE6下解析有問題,我們知道就width來說,一個塊級元素的magin、padding、boder,width7個屬性的寬度之和,應該等於其父級元素的內容區域(width),而我們一般設定寬度若是未達到其長度,瀏覽器就會重置margin-right的值,將之它們的和等於其值,當然若是我們為margin設定負值,那麼元素的width可能超出其父元素。

  在標準下,width為padding所佔區域,但是再ie6中設定width後,其真實width為所設width-其padding與border*2,我一般採用CSShack技術處理

  ② IE6的雙倍邊距BUG,在塊級元素浮動後本來外邊距10px,但IE解釋為20px,解決辦法是加上display: inline

  問題:在IE6下如果某個標籤使用了float屬性,同時設定了其外補丁“margin:10px 0 0 10px”可以看出,上邊距和左邊距同樣為10px,但第一個物件距左邊有20px。

  解決辦法:當將其display屬性設定為inline時問題就都解決了。

  說明:這是因為塊級物件預設的display屬性值是block,當設定了浮動的同時,還設定了它的外邊距 就會出現這種情況。

  也許你會問:“為什麼第二個物件和第一個物件之間就不存在雙倍邊距的BUG”?

  因為浮動都有其相對應的物件,只有相對於其父物件的浮動 物件才會出現這樣的問題。

  第一個物件是相對父物件的,而第二個物件是相對第一個物件的,所以第二個物件在設定後不會出現問題。

  另外在一些特殊佈局中,可能需要組合使用display:block;和display:inline;才能達到預期效果。

  當然最壞的情況下,我們就可以使用”margin:10px 0 0 10px;*margin:10px 0 0 10px;_margin:10px 0 0 5px”,

  這種“標準屬性;*IE7識別屬性;_IE6識別屬性”HACK方式解決

  總結:這個現象僅當塊級物件設定了浮動屬性後才會出現,內聯物件(行級物件)不會出現此問題。並且只有設定左邊距和右邊距的值才會出問題,上下邊距不會出現問題。

<div style="width:200px;height:50px;background:#ccc;">
<div style="width:100px; height:50px;float:left;margin-left:10px; background:#eee;">
</div>
</div>

  margin雙佈局可以說是IE6下經典的bug之一。產生的條件是:block元素+浮動+margin。

  還記得我自認為會css的那個階段,這個問題我經常碰到,會很熟練的用hack解決這個問題,當時還自以為是,洋洋得意。現在看來,當時的自己嫩的就像個 豆芽菜。

  真正css厲害的人基本上是不會碰到這個bug的,如果您時不時遇到這個bug,說明您的css還有好一段路要走。

  我的體會是越少的浮動,就會越少的程式碼,會有更靈活的頁面,會有擴充套件性更強的頁面。這不多說,歸結為到一定水平了,浮動會用的較少。

  另外,您也會避免使用浮動+margin的用法。所以,越後來越不易遇到這種bug。

  這裡提一下解決方法,使用hack我是不推薦的,使用hack屬於比初學者稍高一點的層次水平。一個頁面,沒有一個hack,但是各個瀏覽器下表現一致,這才是水平。

  使用display:inline;可以解決這個問題。

  而為什麼display:inline可以解決這個雙邊距bug,首先是inline元素或inline-block元素是不存在雙邊距問題的。

  然後,float:left等浮動屬性可以讓inline元素haslayout,會讓inline元素表現得跟inline-block元素的特性一樣, 支援高寬,垂直margin和padding等,所以div class的所有樣式可以用在這個display inline的元素上。

  以上便是我所記得的一些bug,在這裡我再順帶提一下haslayout(IE8廢棄該屬性)。

  在IE低版本瀏覽器時基本是表格佈局的時代,幾乎是所有的元素(除內聯元素)都是一個盒子,內容不會超過表格的單元格,表格的單元格也不會超出表格。

  在IE6推出後,CSS改變這一假設——因為CSS允許內容超出元素。 因此haslayout這個屬性就誕生了。

  在IE6,IE7中,每個元素都有haslayout這個屬性,可以設定為 true 或者 false。

  如果設定為true,元素就必須去自我佈局和渲染,因此元素會擴充套件去包含它溢位的內容,例如浮動或沒截斷的單詞。

  如果haslayout 沒有被設定成true,那麼元素需依靠某個祖先元素來渲染它。這就是很多的ie bugs誕生的地方。IE瀏覽器下的很多bug都是haslayout = false 引起的,

  layout元素有以下特點:

  擁有佈局(haslayout=true)元素不會收縮,所以可能會發生文字截斷、消失的現象;

  佈局元素對浮動自動清理;

  相對定位的元素沒有佈局,這可能導致絕對元素定位偏差;

  擁有佈局的元素外邊距不疊加;

  滾動時,頁面會有所跳動;

  邊框消失

  畫素偏差

  haslayout不是一個CSS屬性,所以我們不能這樣的來設定它 haslayout:true;

  一個元素被設定成haslayout:true將被渲染成一個 having haslayout,

  反之同理。 一些元素本身該屬性為true,若是需要觸發,最好的方法是設定其zoom屬性; 哪些元素本身就 haslayout:true

  <html>, <body><table>, <tr>, <th>, <td><iframe>, <embed> (non-standard element),

  <object>, <applet> <img><hr><input>, <button>, <select>, <textarea>, <fieldset>, <legend>

  zoom:1,被認為是最好的觸發Layout的方法,因為它對當前元素沒有影響。 觸發haslayout,相對來說比haslayout=false要簡單。

  以下屬性和值將給定一個元素進行佈局

  position: absolute float:    left or right display:    inline-block;width:   any value other than auto;

  height:    any value other than auto;zoom:   any value other than normal (*);writing-mode:  tb-rl

  最後,因為各個瀏覽器對一些元素的預設值設定不一致也會導致表現差異,比如瀏覽器預設字型,預設行高,預設間距等。所以我們一般會為幾個主要元素設定預設值。

  結語

  以上便是我對瀏覽器相容的簡單認識,但是還是有很多不足的地方,由於技術所限,這裡提出來和各位高手交流,希望在交流學習中和以後工作中積累相關經驗,做出滿足主流瀏覽器的網頁。

相關文章