所謂的瀏覽器兼容性問題,是指由於不一樣的瀏覽器對同一段代碼有不一樣的解析,形成頁面顯示效果不統一的狀況。在大多數狀況下,咱們的需求是,不管用戶用什麼瀏覽器來查看咱們的網站或者登錄咱們的系統,都應該是統一的顯示效果。因此瀏覽器的兼容性問題是咱們web前端開發人員常常會碰到和必需要解決的問題.javascript
歸納的來講,瀏覽器兼容指的是同一份代碼在不一樣的瀏覽器顯示效果是不一樣的。
瀏覽器的兼容性大致分爲樣式兼容性(css),交互兼容性(javascript),瀏覽器 hack 三個方面。css
一些概念:html
Css樣式在各瀏覽器中解析不一致的狀況,或者說Css樣式在瀏覽器中不能正確顯示的問題稱爲CSS Bug前端
CSS中,hack是指一種兼容css在不一樣瀏覽器中正確顯示的技巧方法,由於他們都屬於我的對css代碼的非官方的修改,或非官方的補丁。有些人更喜歡使用patch(補丁)來描述這種行爲。html5
它是一種對特定的瀏覽器或瀏覽器組顯示或隱藏規則或聲明的方法。本質上講,filter是一種用來過濾不一樣瀏覽器的hack類型。java
那麼,node
首先,讓咱們簡單瞭解一下,三種兼容性的不一樣:jquery
1.由於歷史緣由,不一樣的瀏覽器樣式存在差別,能夠經過 Normalize.css 抹平差別,也能夠定製本身的 reset.css,例如經過通配符選擇器,全局重置樣式android
{ margin: 0; padding: 0; }
2.在CSS3尚未成爲真正的標準時,瀏覽器廠商就開始支持這些屬性的使用了。CSS3樣式語法還存在波動時,瀏覽器廠商提供了針對瀏覽器的前綴,直到如今仍是有部分的屬性須要加上瀏覽器前綴。在開發過程當中咱們通常經過IDE開發插件、css 預處理器以及前端自動化構建工程幫咱們處理。ios
瀏覽器內核與前綴的對應關係以下
內核 | 主要表明的瀏覽器 | 前綴 |
---|---|---|
Trident | IE瀏覽器 | -ms |
Gecko | Firefox | -moz |
Presto | Opera | -o |
Webkit | Chrome和Safari | -webkit |
3.在還原設計稿的時候咱們經常會須要用到透明屬性,因此解決 IE9 如下瀏覽器不能使用 opacit。
opacity: 0.5; filter: alpha(opacity = 50); //IE6-IE8咱們習慣使用filter濾鏡屬性來進行實現 filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50); //IE4-IE9都支持濾鏡寫法progid:DXImageTransform.Microsoft.Alpha(Opacity=xx)
1.事件兼容的問題,咱們一般須要會封裝一個適配器的方法,過濾事件句柄綁定、移除、冒泡阻止以及默認事件行爲處理
var helper = {} //綁定事件 helper.on = function(target, type, handler) { if(target.addEventListener) { target.addEventListener(type, handler, false); } else { target.attachEvent("on" + type, function(event) { return handler.call(target, event); }, false); } }; //取消事件監聽 helper.remove = function(target, type, handler) { if(target.removeEventListener) { target.removeEventListener(type, handler); } else { target.detachEvent("on" + type, function(event) { return handler.call(target, event); }, true); } };
2.new Date()構造函數使用,'2018-07-05'是沒法被各個瀏覽器中,使用new Date(str)來正確生成日期對象的。 正確的用法是'2018/07/05'.
3.獲取 scrollTop 經過 document.documentElement.scrollTop 兼容非chrome瀏覽器
var scrollTop = document.documentElement.scrollTop||document.body.scrollTop;
解決瀏覽器兼容的主要方法是css hack 那麼到底什麼是css hack呢?
因爲不一樣廠商的流覽器或某瀏覽器的不一樣版本(如IE6-IE11,Firefox/Safari/Opera/Chrome等),對CSS的支持、解析不同,致使在不一樣瀏覽器的環境中呈現出不一致的頁面展示效果。這時,咱們爲了得到統一的頁面效果,就須要針對不一樣的瀏覽器或不一樣版本寫特定的CSS樣式,咱們把這個針對不一樣的瀏覽器/不一樣版本寫相應的CSS code的過程,叫作CSS hack!
1.快速判斷 IE 瀏覽器版本
<!--[if IE 8]> ie8 <![endif]--> <!--[if IE 9]> 騷氣的 ie9 瀏覽器 <![endif]-->
2.判斷是不是 Safari 瀏覽器
/* Safari */ var isSafari = /a/.__proto__=='//';
3.判斷是不是 Chrome 瀏覽器
/* Chrome */ var isChrome = Boolean(window.chrome);
一、要不要作產品的角度(產品的受衆、受衆的瀏覽器比例、效果優先仍是基本功能優先)成本的角度 (有無必要作某件事)
二、作到什麼程度讓哪些瀏覽器支持哪些效果
三、如何作根據兼容需求選擇技術框架/庫(jquery的版本)根據兼容需求選擇兼容工具(htmlshiv.js、respond.js、css reset、normalize.css、modernizr)postcss
四、漸進加強和優雅降級漸進加強(progressive enhancement):
針對低版本瀏覽器進行構建頁面,保證最基本的功能,而後再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗優雅降級 (graceful degradation): 一開始就構建完整的功能,而後再針對低版本瀏覽器進行兼容。
一、合適的框架Bootstrap (>=ie8);jQuery 1.~ (>=ie6), jQuery 2.~ (>=ie9);Vue (>= ie9)...
二、條件註釋
即IE條件註釋是於HTML源碼中被IE有條件解釋的語句。條件註釋可被用來向IE提供及隱藏代碼。條件註釋 (conditional comment) 是於 HTML 源碼中被IE有條件解釋的語句。條件註釋可被用來向 IE 提供及隱藏代碼。條件註釋最初於微軟的 Internet Explorer 5 瀏覽器中出現,而且直至 Internet Explorer 9 均支持。微軟已宣佈於 IE10 中止支持。
<!--[if IE 6]> <p>You are using Internet Explorer 6.</p> <![endif]--> <!--[if !IE]><!--> <script>alert(1);</script> <!--<![endif]-->
if(若是是)非IE瀏覽器,else(那麼)個人頁面上該 <script>alert(1);</script>標籤會生效,
彈出一個1;若是在IE瀏覽器上,這段自己是有效的,即能控制該效果,因此在其餘瀏覽器這段則會被註釋掉。
<!--[if IE 8]> <link href="ie8only.css" rel="stylesheet"> <![endif]-->
*三、CSS hack
(1)定義:因爲不一樣廠商的瀏覽器,好比Internet Explorer,Safari,Mozilla Firefox,Chrome等,或者是同一廠商的瀏覽器的不一樣版本,如IE6和IE7,對CSS的解析認識不徹底同樣,所以會致使生成的頁面效果不同,得不到咱們所須要的頁面效果。
這個時候咱們就須要針對不一樣的瀏覽器去寫不一樣的CSS,讓它能在不一樣的瀏覽器中也能獲得咱們想要的頁面效果。
(2)常見hack寫法利用該方法去檢測瀏覽器兼容問題
.box{ color: red; _color: blue; /*針對後期檢查將ie6和其餘瀏覽器區別開來的標準*/ *color: pink; /*同上,ie六、7*/ color: yellow\9; /*ie/edge 6-8*/ }
以上屬性均是採用樣式覆蓋形式,去相應地在所在瀏覽器屬性生效
<!–-[if IE 7]> <link rel="stylesheet" href="ie7.css" type="text/css" /> <![endif]–->
(3)常見兼容處理範例
例子A:
.target{ display: inline-block; *display: inline;/*在IE六、7中會生效,產生相似bfc的效果,可添加寬高, 與其餘瀏覽器所使用的display: inline-block;有相同效果*/ *zoom: 1; }
例子B:
.clearfix:after{ content: ''; display: block; clear: both; } .clearfix{ *zoom: 1; /* 僅對ie67有效 */ }
例子C:
.clearfix:after{ content: ''; display: block; clear: both; } .clearfix{ *zoom: 1; /* 僅對ie67有效 */ }
例子D:
<!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]-->
例子E:
<!DOCTYPE html> <!--[if IEMobile 7 ]> <html dir="ltr" lang="en-US"class="no-js iem7"> <![endif]--> <!--[if IE 7 ]> <html dir="ltr" lang="en-US" class="no-js ie7 oldie"> <![endif]-->]--> <!--[if IE 7 ]> <html dir="ltr" lang="en-US" class="no-js ie7 oldie"> <![endif]--> <!--[if IE 8 ]> <html dir="ltr" lang="en-US" class="no-js ie8 oldie"> <![endif]--> <!--[if (gte IE 9)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html dir="ltr" lang="en-US" class="no-js"><!--<![endif]-->
(4)常見屬性的兼容狀況:多使用 https://caniuse.com/
常見的瀏覽器兼容性可分爲三類:
viewport
<meta charset="utf-8"> <!--主要I是強制讓文檔的寬度與設備寬度保持1:1,最大寬度1.0,禁止屏幕縮放。--> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <!--這個也是iphone私有標籤,容許全屏瀏覽。--> <meta content="yes" name="apple-mobile-web-app-capable"> <!--iphone的私有標籤,iphone頂端狀態條的樣式。--> <meta content="black" name="apple-mobile-web-app-status-bar-style"> <!--禁止數字自動識別爲電話號碼,這個比較有用,由於一串數字在iphone上會顯示成藍色,樣式加成別的顏色也是不生效的。--> <meta content="telephone=no" name="format-detection"> <!--禁止email識別--> <meta content="email=no" name="format-detection">
.el { -webkit-user-select: none; -moz-user-select: none; -khtml-user-select: none; user-select: none; }
@media only screen and (min-device-width : 320px) and (max-device-width : 375px){}
方法:能夠用html5的oninput事件去代替keyup
<input type="text" id="testInput"> <script type="text/javascript"> document.getElementById('input').addEventListener('input', function(e){ var value = e.target.value; }); </script>
input,textarea { border: 0; -webkit-appearance: none; }
input:-ms-clear{display:none;}
flex佈局對於低版本的安卓,不支持flex-wrap:wrap屬性,可是ios系統支持換行屬性,這個時候如何解決呢?固然是不使用換行,用其餘方式代替。
.box{ display: -webkit-box; /* 老版本語法: Safari, iOS, Android browser, older WebKit browsers. */ display: -moz-box; /* 老版本語法: Firefox (buggy) */ display: -ms-flexbox; /* 混合版本語法: IE 10 */ display: -webkit-flex; /* 新版本語法: Chrome 21+ */ display: flex; /* 新版本語法: Opera 12.1, Firefox 22+ */ }
line-height: (和input框的高度同樣高)---pc端解決方法 line-height:normal ---移動端解決方法
input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none !important; margin: 0; }
$(function () { //獲取瀏覽器的userAgent,並轉化爲小寫 var ua = navigator.userAgent.toLowerCase(); //判斷是不是蘋果手機,是則是true var isIos = (ua.indexOf('iphone') != -1) || (ua.indexOf('ipad') != -1); if (isIos) { $("input:file").removeAttr("capture"); }; })
這個不是 BUG,因爲自動播放網頁中的音頻或視頻,會給用戶帶來一些困擾或者沒必要要的流量消耗,因此蘋果系統和安卓系統一般都會禁止自動播放和使用 JS 的觸發播放,必須由用戶來觸發才能夠播放。
解決方法思路:先經過用戶 touchstart 觸碰,觸發播放並暫停(音頻開始加載,後面用 JS 再操做就沒問題了)。
document.addEventListener('touchstart',function() { document.getElementsByTagName('audio')[0].play(); document.getElementsByTagName('audio')[0].pause(); });
這個目前沒有好的辦法解決
情景一:頁面有視頻,點擊頁面按鈕顯示彈出層(好比讓用戶輸入用戶信息),這時候視頻會出如今彈出層上面,是否是很-d疼?
方案:點擊按鈕時候把video隱藏hide,關閉彈出層show,過程當中視頻聲音還在
情景二:頁面很長,往下翻滾時,視頻在播放,脫離文檔流
方案:頁面滾動到某一合適位置把video隱藏hide,回滾到某一位置show,過程當中視頻聲音還在
this.value = this.value.replace(/\u2006/g,'');
iOS 瀏覽器橫屏時會重置字體大小,設置 text-size-adjust 爲 none 能夠解決 iOS 上的問題,但桌面版 Safari 的字體縮放功能會失效,所以最佳方案是將 text-size-adjust 爲 100% 。
-webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; text-size-adjust:100%;
緣由:瀏覽器興起初期,爲了判斷用戶是雙擊仍是單擊,就設置了一個時間段300ms,用戶單擊後300ms後作事件處理,若是在300ms內連續點擊,就判斷爲雙擊,作雙擊處理事件。
因此如今用click綁定事件呢,就會有300ms延遲的問題。
300ms尚可接受,不過由於300ms產生的問題,咱們必需要解決。300ms致使用戶體驗並非很好,解決這個問題,咱們通常在移動端用tap事件來取代click事件。
推薦兩個js,一個是fastclick,一個是tap.js
解決 ie9 如下瀏覽器對 html5 新增標籤不識別的問題
html5shiv.js
<!--[if lt IE 9]>
<script type="text/javascript" src="https://cdn.bootcss.com/html5...;></script>
<![endif]-->
解決 ie9 如下瀏覽器不支持 CSS3 Media Query 的問題。
respond.js
<script src="https://cdn.bootcss.com/respo...;></script>
picturefill.js
解決 IE 9 10 11 等瀏覽器不支持 <picture> 標籤的問題
<script src="https://cdn.bootcss.com/pictu...;></script>
高版本的瀏覽器用了低版本的瀏覽器沒法識別的元素,從而致使不能解析。這點主要體如今html5的新標籤上
htmlshim框架可讓低於IE9的瀏覽器支持html5
img的alt屬性,在圖片不存在的狀況下,各瀏覽器的解析不一致
在chrome下顯示的是一張破損的圖片,在ff下顯示的是alt的文字,而在IE中顯示的是破損的圖片加文字
ul標籤內外邊距問題
ul標籤在IE6IE7中,有個默認的外邊距,可是在IE8以上及其餘瀏覽器中有個默認的內邊距
<div id="test"> <p>文字</p> <p>文字</p> <p>文字</p> </div>
IE的打印結果,有3個子節點,而且都爲P元素;非IE則表現出極大的差別:竟然打印出了7個子節點,固然也包括3個P元素子節點在內,除此以外還多了4個nodeType=3的子節點
改寫爲:
<div id="test"><p>文字</p><p>文字</p><p>文字</p></div>
一、圖片間隙
A)div中的圖片間隙(該bug出如今IE6及更低版本中)
描述:在div中插入圖片時,圖片會將div下方撐大三像素。
hack1:將<div>與<img>寫在一行上;
hack2:將<img>轉爲塊狀元素,給<img>添加聲明:display:block;
B)dt,li中圖片間隙(IE6)
hack:添加聲明:display:block;
overflow:hidden;
二、 默認高度(IE6)
描述:在IE6及如下版本中,部分塊元素擁有默認高度(低於18px~22px高度)
hack1:給元素添加聲明:font-size:0;
hack2:給元素添加聲明:overflow:hidden;
三、雙倍浮向(雙倍邊距)
描述:當Ie6及更低版本瀏覽器在解析浮動元素時,會錯誤地把浮向邊邊界加倍顯示。
hack:給浮動元素添加聲明:display:inline;
4 、 百分比bug
描述:在IE6及如下版本中在解析百分比時,會按四捨五入方式計算從而致使50%加50%大於100%的狀況。
hack:給右面的浮動元素添加聲明:clear:right; 意思:清除右浮動。
clear 清除浮動
clear:left;清除左浮動
clear:right;清除右浮動
clear:both 清除兩邊浮動
五、表單元素行高不一致(IE,MOZ,C,O,S)
描述:表單元素行高對齊方式不一致
hack:給表單元素添加聲明:float:left;
六、按鈕元素默認大小不一
描述:各瀏覽器中按鈕元素大小不一致
hack:統一大小
hack2:input外邊套一個標籤,在這個標籤裏寫按鈕的樣式,把input的邊框 和背景色去掉。
hack3:若是這個按鈕是一個圖片,直接把圖片做爲按鈕的背景圖便可。
瀏覽器解析按鈕邊框時,會把邊框解析在按鈕內部,不會影響按鈕的原有大小
7)透明屬性
IE瀏覽器寫法:filter:alpha(opacity=value);
兼容其餘瀏覽器寫法:opacity:.value;(value的取值範圍0-9)
在IE6及更低版本的瀏覽器裏,若是想去掉input的默認邊框,需將其border屬性值設置成0方可兼容多個瀏覽器。
bug:子元素沒設置任何浮動,設置了margin-top屬性後,會錯誤的把margin-top的屬性值添加給父元素.(塊元素)
hack1:給父元素添加overflow:hidden;聲明。
若是父元素設置了浮動屬性也不會出現這個問題。
在屬性前可加以上這三個符號
_ 只有IE6如下支持,例如_height:100px;
+只有IE7如下支持,例如+height:100px;
針對IE8加屬性值後綴0(數字零),例如:height:200px0;
!important優先級聲明,只有高版本支持,IE6不支持
main{height:60px!important;}
解決方法:
例如:
main{height:60px!important;height:70px;}
注:同時設兩個高度,優先級聲明的屬性要放到前面。
var winW=document.body.clientWidth||document.docuemntElement.clientWidth;//網頁可見區域寬 var winH=document.body.clientHeight||document.docuemntElement.clientHeight;//網頁可見區域寬 //以上爲不包括邊框的寬高,若是是offsetWidth或者offsetHeight的話包括邊框 var winWW=document.body.scrollWidth||document.docuemntElement.scrollWidth;//整個網頁的寬 var winHH=document.body.scrollHeight||document.docuemntElement.scrollHeight;//整個網頁的高 var scrollHeight=document.body.scrollTop||document.docuemntElement.scrollTop;//網頁被捲去的高 var scrollLeft=document.body.scrollLeft||document.docuemntElement.scrollLeft;//網頁左卷的距離 var screenH=window.screen.height;//屏幕分辨率的高 var screenW=window.screen.width;//屏幕分辨率的寬 var screenX=window.screenLeft;//瀏覽器窗口相對於屏幕的x座標(除了FireFox) var screenXX=window.screenX;//FireFox相對於屏幕的X座標 var screenY=window.screenTop;//瀏覽器窗口相對於屏幕的y座標(除了FireFox) var screenYY=window.screenY;//FireFox相對於屏幕的y座標
二、event事件問題
/event事件問題 document.onclick=function(ev){//谷歌火狐的寫法,IE9以上支持,往下不支持; var e=ev; console.log(e); } document.onclick=function(){//谷歌和IE支持,火狐不支持; var e=event; console.log(e); } document.onclick=function(ev){//兼容寫法; var e=ev||window.event; var mouseX=e.clientX;//鼠標X軸的座標 var mouseY=e.clientY;//鼠標Y軸的座標 }
三、DOM節點相關的問題
function nextnode(obj){//獲取下一個兄弟節點 if (obj.nextElementSibling) { return obj.nextElementSibling; } else{ return obj.nextSibling; }; } function prenode(obj){//獲取上一個兄弟節點 if (obj.previousElementSibling) { return obj.previousElementSibling; } else{ return obj.previousSibling; }; } function firstnode(obj){//獲取第一個子節點 if (obj.firstElementChild) { return obj.firstElementChild;//非IE678支持 } else{ return obj.firstChild;//IE678支持 }; } function lastnode(obj){//獲取最後一個子節點 if (obj.lastElementChild) { return obj.lastElementChild;//非IE678支持 } else{ return obj.lastChild;//IE678支持 }; }
四、document.getElementsByClassName問題
//經過類名獲取元素 document.getElementsByClassName('');//IE 6 7 8不支持; //這裏能夠定義一個函數來解決兼容問題,固然別在這給我提jQuery... //第一個爲全局獲取類名,第二個爲局部獲取類名 function byClass1(oClass){//全局獲取,oClass爲你想要查找的類名,沒有「.」 var tags=document.all?document.all:document.getElementsByTagName('*'); var arr=[]; for (var i = 0; i < tags.length; i++) { var reg=new RegExp('\\b'+oClass+'\\b','g'); if (reg.test(tags[i].className)) { arr.push(tags[i]); }; }; return arr;//注意返回的也是數組,包含你傳入的class全部元素; } function byClass2(parentID,oClass){//局部獲取類名,parentID爲你傳入的父級ID var parent=document.getElementById(parentID); var tags=parent.all?parent.all:parent.getElementsByTagName('*'); var arr=[]; for (var i = 0; i < tags.length; i++) { var reg=new RegExp('\\b'+oClass+'\\b','g'); if (reg.test(tags[i].className)) { arr.push(tags[i]); }; }; return arr;//注意返回的也是數組,包含你傳入的class全部元素; }
五、獲取元素的非行間樣式值
//獲取元素的非行間樣式值 function getStyle(object,oCss) { if (object.currentStyle) { return object.currentStyle[oCss];//IE }else{ return getComputedStyle(object,null)[oCss];//除了IE } }
六、設置監聽事件
function addEvent(obj,type,fn){//添加事件監聽,三個參數分別爲 對象、事件類型、事件處理函數,默認爲false if (obj.addEventListener) { obj.addEventListener(type,fn,false);//非IE } else{ obj.attachEvent('on'+type,fn);//ie,這裏已經加上on,傳參的時候注意不要重複加了 }; } function removeEvent(obj,type,fn){//刪除事件監聽 if (obj.removeEventListener) { obj.removeEventListener(type,fn,false);//非IE } else{ obj.detachEvent('on'+type,fn);//ie,這裏已經加上on,傳參的時候注意不要重複加了 }; }
七、元素到瀏覽器邊緣的距離
function offsetTL(obj){//獲取元素內容距離瀏覽器邊框的距離(含邊框) var ofL=0,ofT=0; while(obj){ ofL+=obj.offsetLeft+obj.clientLeft; ofT+=obj.offsetTop+obj.clientTop; obj=obj.offsetParent; } return{left:ofL,top:ofT}; }
八、阻止默認事件
//js阻止默認事件 document.onclick=function(e){ var e=e||window.event; if (e.preventDefault) { e.preventDefault();//W3C標準 }else{ e.returnValue='false';//IE.. } }
九、關於EVENT事件中的target
//關於event事件中的target document.onmouseover=function(e){ var e=e||window.event; var Target=e.target||e.srcElement;//獲取target的兼容寫法,後面的爲IE var from=e.relatedTarget||e.formElement;//鼠標來的地方,一樣後面的爲IE... var to=e.relatedTarget||e.toElement;//鼠標去的地方 }
十、鼠標滾輪滾動事件
//鼠標滾輪事件 //火狐中的滾輪事件 document.addEventListener("DOMMouseScroll",function(event){ alert(event.detail);//若前滾的話爲 -3,後滾的話爲 3 },false) //非火狐中的滾輪事件 document.onmousewheel=function(event){ alert(event.detail);//前滾:120,後滾:-120 }
完結