前端兼容性问题总结

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,解决方式有四种:

  1. 在元素中插入空注释 ``
  2. 在元素中插入空格
  3. 加入 css: overflow:hidden;
  4. 加入 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

  1. innerText 和 textContent 的作用相同
  2. innerText IE8之前的浏览器支持
  3. innerContent 老版本的Firefox支持
  4. 新版本的浏览器两种方式都支持

和以上四种情况完全一致的还有parentElement(老IE)和parentNode

获取兄弟节点/元素的兼容性问题

ie8以前不支持previousElementSiblingnextElementSibling,以及诸如此类带有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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容