`
white_crucifix
  • 浏览: 95643 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

与IE兼容性纠缠的这几个月

阅读更多
今年过年回来以后,接手一个由公司在其他省市研发部门开发的系统,由于产品刚上线使用,还存在着很多bug,由我和研发部门的同事一起负责修改bug。

这其中就有比较多的IE兼容性问题,由于最初设计者不怎么愿意去迁就IE,最后勉强答应下来至少兼容IE8,结果就是部分页面在IE8下也无法满意。而我们这种行业软件,大多数用户还都是IE7(IE8兼容模式),所以这个问题是避不掉的。花了很多时间来搞,也从中学到些有意思的东西。

内容不分先后主次,想到什么说什么,有的也记不清是IE7还是8,统称旧版IE。

从bootstrap讲起,我们都知道bootstrap是html5和css3的拥护者,这使得如果什么都不处理,在IE78里会出现各种问题。

比如本该在页面两端有两竖条留白,在IE8会被吃掉;比如使用bootstrap的12等分相关class时,IE8完全无效。前者用到的class为.container,后者用到的是诸如col-md-1。因为两者都使用到了css3的@media特性,用以计算width。旧版IE当然不认识啦,当然让旧版IE中实现同样的效果,已经有人帮忙我们做好了。
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->


其中,respond.js正是解决这个问题的关键。另外,html5shiv.js也是必不可少的,其中会帮忙一些兼容问题,具体我没碰到,所以举不出例子。

当然,当你使用bootstrap时,千万别忘了,页面头上的声明
<!DOCTYPE html>

以及head里的声明
<meta http-equiv="X-UA-Compatible" content="IE=edge">


以上,算是热热身,很多时候我们开始做系统时,把bootstrap官网的例子先拷过来,那么通常就遇不到以上问题了。我是因为接手系统,事先没想到以上的设置不全,才有所感慨。

1. $("xxx").attr('href')
看起来是个很显而易见的结果,就是把元素a标签里的href属性的值取出来。但是当href值是相对路径时,比如/开头的,高级浏览器依然按部就班的该是什么值给你什么值,而旧版IE会自说自话给你前面加上浏览器地址栏上的url。
   
2. $("xxx").attr('onclick','window.open(xxxxxxx)')
通常我们给某个元素添加onclick事件么,就直接写在元素上了,又或者可以通过jquery去绑定,而这里至于想通过attr的方式去赋值事件,也是由于项目某个地方的代码逻辑,逼的这里只能这么做。

那么这样做,会有什么问题么?会!在IE7上,事件不会生效!我的猜测是,ie7认为只是给'onclick'这个名字赋了一个'window.openxxxxx'的字符串值。

所以这个地方最佳的方式是通过jquery绑定,但这样做,对另外一个功能有影响,那个功能里,需要复制元素到新的位置,实现是先取出元素html字符串,处理后再append到新位置。因此会导致jquery绑定事件丢失。

于是我很纳闷,开始用很挫的办法,页面头加个IE7判断,里边赋值window.ie = 7, 下面代码判断window.ie === 7,分支内使用jquery绑定,因为此时attr方式失效,最终事件依然绑定了一次,而非两次(如果不加if ie7判断,bind和attr都写,chrome里会触发两次事件)

这里有个有意思的现象,虽然attr在ie7下失效,但是前面说的过程,复制html字符串到新的位置后,新元素的attr居然生效的。这样正好使得,复制后jquery绑定失效,attr又担负起了事件触发的责任。

但是最终还是觉得搓,所以我去重构了那个复制html的逻辑,不再使用html字符串,而是使用jquery对象本身。于是后面就大胆的使用jquery绑定,而不是attr。搞定!

3. console.log, JSON.parse
这个了解的人比较多吧,旧版IE对console对像和JSON对像都不认识。一种比较优雅的办法,就是自己写一组console方法和JSON方法,然后在页面头通过<!--[if lt IE 9]>分支里导入js。

4. html字符串中,尾标签多了少了
由于系统使用backbone来做,需要通过字符串的形式写html模板来构建自定义组件,而一个复杂的字符串html会让你写起来或者读起来吐血。

这里值得称赞的是,ES6和reactJS的字符串模板特性,确实有诚意,虽然scala也早有这种特性。

好吧,我要说的是,我们的代码中,有几个地方都有笔误,多一个</div>, 少一个</div>,<form>写成<from>。。。结果要么导致了$("#xxx")取不到东西,要么导致了css选择器找不到目标,而且都tm发生在旧版IE上,chrome什么的居然都tm能扛过去。

5. z-index
这个绝对是IE7的深坑!坑中之坑!连IE8都不这么玩的。

先说说常规的原理:
<div id='1' ></div>
<div id='2' ></div>


忽略了其他样式,就理解为一个div是一个面板。

上面两个div,从z-index 来讲,2要高于1,后面的高于前面的,这是规定,表问为什么

再来看一个:
<div id='1' >
  <div id='3' style='z-index:1000'></div>
</div>
<div id='2' ></div>


那么这里谁最高呢?当然大家都会觉得是3,确实是3。

现在我们用IE7来打开上面的UI,会是什么结果呢?div2在最高处!挡住了div3。因为IE7对"后面的高于前面"的原则更强制,由于div3属于div1,因此div2要比1和3两者都要高,无论你div3的z-index多大,天王老子来了也不行。如果你想要让3跑到2之上,你就必须设置div1的z-index大于div2就可以了。

这里一个现实的例子就是。div3的位置是一个下拉列表,所以必须浮在所有东西之上,而恰恰在IE7下,它被div2给挡住了。

看了这篇文章后有所启发 http://www.cnblogs.com/darren_code/archive/2012/03/05/z-index.html

以上,我没有谈到一个关键的专业术语,stack context,只是讲讲表象而已。


6. 旧版IE的大写元素名
如果你在旧版IE中查看元素,你会发现很多都是大写DIV,大写TABLE,即便你页面中写的是小写。首先会在你通过jquery取html字符串处理时造成一点影响,但还不至于诡异。

bootstrap中有个.form-inline的样式,目的是将内部的div都处在一行,使用了display:inline或者inline-block样式。其中有一段css选择器,通过ie开发者工具看是类似
.form-inline DIV {
   display: inline
}

但奇怪的是,页面中.form-inline内部的div却没有受到这个样式影响,每个div依然猖狂的占了一整行。然后,通过查看页面元素,我惊奇的发现,html元素居然都是小写。我忽然想到,这里是通过backbone的组件渲染方式来构建出页面元素的,换句话说,是在浏览器首次加载完页面以后,再把组件元素贴到目标出。这样一来,在backbone组件的字符串模板里写的小写,到了页面上也是保持小写。而使得前面的css失效。

然后我做了个尝试,在页面上自己写了一个css

.form-inline div{
   display: inline
}


注意,换成小写了。但tm运行结果一看,被IE又强制转成大写了,无语。最终换了个样式,用了  .form-inline .form-group,虽然不全面,但是够用了





想了想说的差不多了,但是这个过程还在继续。系统中某个变态的页面在IE7下还是一滩浆糊,任重而道远啊卧槽。
2
1
分享到:
评论
2 楼 white_crucifix 2015-07-08  
dieslrae 写道
上次项目让我兼容ie6,我的表情就直接告诉他"你特么是在逗我?","请滚开好吗?",还在兼容ie8以下版本都是上辈子折了杰宝的天使


好吧,我们都找不到装ie6的机器了。。
1 楼 dieslrae 2015-07-05  
上次项目让我兼容ie6,我的表情就直接告诉他"你特么是在逗我?","请滚开好吗?",还在兼容ie8以下版本都是上辈子折了杰宝的天使

相关推荐

Global site tag (gtag.js) - Google Analytics