前端相容性問題總結
HTML 篇
樣式相容性問題
<!-- IE 按 Edge 模式渲染 -->
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!-- IE 8 9 10 按 IE7 模式渲染 -->
<meta http-equiv="X-UA-Compatible" content="IE=Emulate7" />
怪異模式
怪異模式是沒有遵守 W3C 規範的一種相容模式,其中的 width 是包括 contentWidth, 左右padding, 左右border 在內的全部範圍(height 也一樣),類似於 box-sizing: border-box;
,而且 table 的 font-size 不能從父元素繼承。以下情況會觸發瀏覽器怪異模式(Quirks Mode):
- 沒寫 DOCTYPE 觸發怪異模式
- 在
<!DOCTYPE ...>
前加<?xml version="1.0" encoding="utf-8" ?>
, IE6 下會觸發怪異模式 - 在
<!DOCTYPE ...>
前加入``, IE7進入怪異模式 -
<!DOCTYPE ...>
前有任何非空字元,會在IE6 下會觸發怪異模式 -
<!DOCTYPE ...>
前有 XML ,在IE7 下不會觸發怪異模式,但不能有其他非空字元
檢查document.compatMode
,可以檢視瀏覽器工作在哪個模式:值BackCompat
為怪異模式,值CSS1Compat
為標準模式
display:inline-block 元素間有間隙
<!-- 以下的 li 元素是 display: inline; 型別的 -->
<!-- 這樣寫元素之間有間隙 -->
<ul>
<li>apple</li>
<li>banana</li>
<li>pineapple</li>
<li>peach</li>
<li>orange</li>
</ul>
<!-- 換個寫法解決問題-->
<ul>
<li>apple</li><li>
banana</li><li>
pineapple</li><li>
peach</li><li>
orange</li>
</ul>
IE可能出現的文件樣式短暫失效問題
<head>
<!-- meta部分 -->
<title></title>
<!-- 可能的script部分 -->
<script type="text/javascript"></script> <!-- 關鍵:新增一個空標籤 -->
<!-- link部分 -->
</head>
css 篇
雙倍間距問題
/*一下程式碼在 IE6 中會出現雙倍間距*/
#box{
float: left;
margin: 10px;
}
//解決方法
#box{
float: left;
margin: 10px;
display: inline;
}
錯位問題
/*IE6中,這樣的多個盒子並列時會發生向下偏移,應該對偏移的盒子新增負 margin-top 進行修正*/
.box{
float: left;
}
IE6 奇數寬高問題
IE6 中盒子的寬(width) 和高(height)設定為奇數時會有 bug,儘量設定為偶數即可。
IE6 Peekaboo Bug
一個 div#top 中加入一個 div#float 向左浮動,然後加入一個或多個 div, 直到清除浮動為止:
<style>
#top{
border: dotted 2px black;
background: #eee; /*top有背景*/
}
#float{
height: 196px;
width: 196px;
border: 2px solid red;
}
.border{
border: 2px solid green;
}
.clear{
clear: both;
border: 2px solid blue;
}
</style>
<body>
<div id="top">
<div id="float">float div</div>
<!-- 這以下在 IE6 中不能正常顯示 -->
<div class="border">inside-div text!</div>
<div class="border">inside-div text!</div>
<!-- 這以上在 IE6 中不能正常顯示 -->
<div class="clear">clear div</div>
</div>
</body>
解決方法,給 #top 一個 height 或 width :
#top{
height: 300px;
}
盒子坍塌
這個問題比較普遍,在盒內層元素設定外邊距時會發生
/*發生盒子坍塌*/
#box{
height: 300px;
}
#box .inner-box{
margin:20px;
}
/*修正*/
#box{
height: 300px;
margin-top: -20px;
}
#box .inner-box{
margin:20px;
}
文字大小
字型大小在不同瀏覽上不一致。例如font-size:14px
,在 IE 中的實際行高是16px,下面有3px留白;在 Firefox 中的實際行高是17px,下面有3px留白,上邊1px留白;在 opera 中就更不一樣了。解決方式統一指定行高 line-height
html{
font-size: 14px;
line-height: 14px;
}
另外,我們會遇到 font-size:62.5%
這樣的定義,為了把預設的 16px 對映為 10px, 這樣1em = 10px 更利於計算。
去除元素預設邊距
有很多元素預設帶有邊距,對我們排版很不利。但利用萬用字元*
去除邊距存在效能問題,所以用下面語句清除預設邊距
body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend,button,input,textarea,th,td{
margin: 0;
padding: 0;
}
低版本 IE 高度限定失效
一般的元素指定高度屬性 height 可以固定該元素高度,但在低版本 IE 中無法固定元素高度,該元素高度依然會被內容撐開,需要注意。(寬度也一樣)
IE6 不支援 png 透明效果
解決方式用濾鏡
#box{
_background: none;
filter: progid:DXImageTransForm.Microsoft.AlphaImageLoader(src='路徑');
}
Firefox 的寬度問題
Firefox瀏覽器會的 body 比其他瀏覽器的 body 寬度小1個畫素,注意設定其子元素(尤其 float 元素大小,防止排版混亂。
IE6中的吞吃問題
IE6 中為上下2個 div 中的上一個地址設定背景時,下一個 div 也會帶有背景。類似的還有 overflow:scroll
時,出現的滾動條不完整。應該 分別對在上方的 div 和滾動條不完整的 div 加 zoom: 1
樣式。
IE6 圖片格式問題
IE6 中的圖片預設存在邊框,應統一去除。同時圖片下方會有空隙,用 font-size解決
img{
border: none;
font-size: 0;
}
IE中無法定義1px高度這樣的小盒子
IE6 中的空元素高度不能低於19px,解決方式有四種:
- 在元素中插入空註釋 ``
- 在元素中插入空格
- 加入 css: overflow:hidden;
- 加入 css: font-size: 0;
IE6 z-index 失效
當父元素已設定 z-index 屬性後,子元素的 z-index 會失效。
IE6中 select 始終高於 div
浮層 div 出現時隱藏 select,浮層 div 消失時再顯示 select。
讓 chrome 支援小於 12px 的字型
#box{
font-size: 8px;
-webkit-text-size-adjust: none;
}
/* 但是,上面這個方法 chrome27 以後就不能用了。但我們可以用 css3 解決這個問題 */
#box{
font-size: 12px;
-webkit-transform: scale(0.75);
}
CSS Hack
相容性屬性設定,注意書寫順序:優先寫高等級瀏覽器支援方式、優先寫支援瀏覽器多的方式
/*以 color 屬性為例,注意書寫順序*/
#box{
color: #f00; //所有瀏覽器都支援
color: #0f0 !important; //只有 IE6 無效
color: #00f\9; //所有 IE 都有效
color: #ff0\0; //IE8+ 有效
color: #f0f\9\0; //IE9+ 有效
*color: #fff; //僅 IE6, IE7 有效
#color: #0ff; //僅 IE6, IE7 有效
+color: #800; //僅 IE6, IE7 有效
-color: #008; //只有 IE6 有效
_color: #080; //只有 IE6 有效
}
由於後定義的屬性覆蓋先定義的屬性,所有上面設定最後的效果為:
IE6 為 #080
IE7 為 #800
IE8 為 #ff0
IE9,10 為 #0f0
其他 為 #f00
javascript 篇
innerText 和 innerContent
- innerText 和 textContent 的作用相同
- innerText IE8之前的瀏覽器支援
- innerContent 老版本的Firefox支援
- 新版本的瀏覽器兩種方式都支援
和以上四種情況完全一致的還有parentElement(老IE)和parentNode
獲取兄弟節點/元素的相容性問題
ie8以前不支援previousElementSibling
和nextElementSibling
,以及諸如此類帶有Element的元素屬性。利用previousSibling
和nextSibling
等不帶Element的屬性實現如下:
// 獲取下一個緊鄰的兄弟元素
function getNextElement(element){
var ele = element;
if(ele.nextElementSibling) return ele.nextElementSibling;
do{
ele = ele.nextSibling;
}while(ele && ele.nodeType !== 1);
return ele;
}
// 獲取上一個緊鄰的兄弟元素
function getPreviousElement(element){
var ele = element;
if(ele.perviousElementSibling) return ele.perviousElementSibling;
do{
ele = ele.perviousSibling;
}while(ele && ele.nodeType !== 1);
return ele;
}
// 獲取第一個子元素
function getFirstElement(parent){
if(parent.firstElementChild) return parent.firstElementChild;
var ele = parent.firstChild;
while(ele && ele.nodeType !== 1) ele = ele.nextSibling;
return ele;
}
// 獲取最後一個子元素
function getLastElement(parent){
if(parent.LastElementChild) return parent.LastElementChild;
var ele = parent.lastChild;
while(ele && ele.nodeType !== 1) ele = ele.perviousSibling;
return ele;
}
// 獲取所有兄弟元素
function sibling(ele){
if(!ele) return null;
var elements = [ ];
var el = ele.previousSibling;
while(el){
if(el.nodeType === 1)
elements.push(el);
el = el.previousSibling;
}
el = element.nextSibling;
while(el){
if(el.nodeType === 1)
elements.push(el);
el = el.nextSibling;
}
return elements;
}
其它DOM操作
IE中有一些很好用的 DOM 方法,但是其他瀏覽器卻沒有,比如:
-
ele.swapNode(anotherEle)
用來交換節點; -
ele.removeNode()
刪除當前節點; -
ele.insertAgjacentHTML('position','HTMLText')
和ele.insertAgjacentHTML('position',ele)
用來插入節點;
部分實現方式寫在下面:
//實現swapNode方法
if(window.Node && !Node.prototype.swapNode){
Node.prototype.swapNode = function(node){
var nextSibling = this.nextSibling;
var parentNode = this.parentNode;
node.parentNode.replaceChild(this, node);
parentNode.insertBefore(node, nextSibling);
}
}
//實現removeNode
if(window.Node && !Node.prototype.removeNode){
Node.prototype.removeNode = function(){
this.parentNode.removeChild(this);
}
}
//insertAdjacentHTML和insertAdjacentElement可以用insertBefore代替
//由於有現成方法替換,這裡不寫具體實現了
js 操作 css 相容性
//透明度
//非IE方法
ele.style.opacity = 0.2; //0-1
//IE
ele.style.filter = "alpha(opacity=100)";
//float屬性
//非IE
ele.style.float = "left";
//IE
ele.style.cssFloat = "left";
Array方法
array.filter();
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisArg */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var res = [];
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++){
if (i in t){
var val = t[i];
if (fun.call(thisArg, val, i, t))
res.push(val);
}
}
return res;
};
}
array.forEach();
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback, thisArg) {
var T, k = 0;
if (this == null) {
throw new TypeError(' this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (typeof callback !== "function") {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) T = thisArg;
while (k < len) {
var kValue;
if (k in O) {
kValue = O[k];
callback.call(T, kValue, k, O);
}
k++;
}
return undefined;
};
}
註冊事件
標準的繫結方法有兩種,addEventListener和attachEvent前者是標準瀏覽器支援的API,後者是IE8以下瀏覽器支援的API:
//例如給一個button註冊click事件
var el = document.getElementById('button'); //button是一個<button>元素
var handler = function(e){alert("button clicked.");};
if(el.addEventLister){
el.addEventListener("click", handler,false);
}
if(el.attachEvent){
el.attachEvent("onclick", handler);
}
需要注意的是:
- addEventLister的第一個引數事件型別是不加on字首的,而attachEvent中需要加on字首;
- addEventLister中的事件回撥函式中的this指向事件元素target本身,而attachEvent中的事件回撥函式的this指向的是window;
- addEventLister有第三個引數,true表示事件工作在捕獲階段,false為冒泡階段(預設值:false)。而attachEvent只能工作在冒泡階段;
- 解除事件方法標準方法removeListen(),在IE8中,對應使用detachEvent()。注意,他們和上面的註冊方法一一對應,不能混用;
- 阻止預設事件標準方法 event.preventDefault(), 在IE8中,使用 event.returnValue = false;
- 阻止冒泡的方法 event.stopPropagation(), 在IE8中,使用 event.cancelBubble = true;
- 老版本 IE 中,事件函式內部的 this 不是被監聽元素本身,而是 window 。故應該使用 call 改變 this 指向。
事件物件
-
e.eventPhase
事件階段,IE8及以前不支援,因為那時不支援捕獲 -
e.target
始終是觸發事件的物件。IE8以前用srcElement - ie8以前用window.event獲得事件物件,而不是回撥函式的引數e
function(e){}
return e || window.event;
}
// 相容target
function(e){
target = e.target || e.srcElement;
//do something else
}
獲取滑鼠在頁面上的位置
ie8以前沒有完整的位置屬性,部分屬性需要通過已有的屬性計算得到:
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
var pageX = e.pageX || e.x || e.clientX + scrollLeft;
var pageY = e.pageY || e.y || e.clientY + scrollTop;
獲取鍵盤事件的鍵值
var keyCode = e.keyCode || e.which;
取消使用者的文字的選擇,移動端很常用
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
使不支援h5的瀏覽器支援h5標籤
<!--[if IE]>
<style>
article, aside, footer, header, nav, section, details, menu, figure {
display: block;
}
canvas, progress, audio, video {
display: inline-block;
}
progress {
vertical-align: baseline;
}
audio:not([controls]) {
display: none;
height: 0;
}
mark {
background-color: #ff0;
color: #000;
}
</style>
<script>
(function() {
if(!/*@cc_on!@*/0)
return;
var e = "abbr, article, aside, audio, bb, canvas, datagrid, datalist, details, dialog, eventsource, figure, footer, header, hgroup, mark, menu, meter, nav, output, progress, section, time, video".split(', ');
var i = e.length;
while(i--) {
document.createElement(e[i]);
}
})();
</script>
<![endif]-->
Ajax 相容問題
//定義一個 XMLHttpRequest 物件
var xhr;
if(XMLHttpRequest){
xhr = new XMLHttpRequest(); //chrome, safari, opera, firefox
} else if(ActionXObject){
try{
xhr = new ActionXObject("Msxml2.XMLHTTP"); //IE 中 Msxml 外掛
}catch(e){
xhr = new ActionXObject("Microsoft.XMLHTTP"); //IE
}
}
綜合篇
處理 html 和 css 編碼不一致問題
在 web.config 中寫以下程式碼
<system.web><globalization fileEncoding="utf-8" resquestEncoding="utf-8" responseEncoding="utf-8" culture="zh-CN" /></system.web>
相關文章
- 前端跨域問題總結前端跨域
- webpack 中版本相容性問題錯誤總結Web
- 前端解決跨域問題總結前端跨域
- PC端/移動端常見的相容性問題總結
- 前端面試總結之:js跨域問題前端面試JS跨域
- 問題總結
- 前端面試題總結——綜合問題(持續更新中)前端面試題
- 前端面試題(總結)前端面試題
- 前端面試題總結前端面試題
- Swoole 問題總結
- Elasticsearch 問題總結Elasticsearch
- Kibana 問題總結
- Kerberos問題總結ROS
- 前端面試題及其總結前端面試題
- 前端React面試題總結前端React面試題
- 跨域問題總結跨域
- springboot使用問題總結Spring Boot
- Fiddler 使用問題總結
- JBoss安全問題總結
- 面試問題總結面試
- electron初探問題總結
- 揹包問題例題總結
- 前端面試題總結(定期更新)前端面試題
- Go mod 相容性問題Go
- input file相容性問題
- ryu啟動問題總結
- flutter安裝問題總結Flutter
- vue專案問題總結Vue
- expdpnf 匯出問題總結
- mysql相關問題總結MySql
- Vue 常見問題總結Vue
- TCP常見問題總結TCP
- RabbitMq面試問題總結MQ面試
- PHP面試問題總結PHP面試
- REDIS面試問題總結Redis面試
- mysql常見問題總結MySql
- Kubernetes 常見問題總結
- Flink 常見問題總結