巧用浏览器CSS属性值的不兼容向下兼容hack技巧

这篇文章发布于 2016年10月25日,星期二,23:16,归类于 CSS相关。 阅读 43568 次, 今日 1 次 31 条评论

 

一、越来越忙,废话就不多说了

越来越忙,废话就不多说了,就少说一点,最近个把月收到了很多偏体验方向的简历,有2个点想槽一下:

  1. 关键要有亮点

    很多人简历就是基本信息,然后巴拉巴拉一些我不熟悉的项目,用了什么框架,自己做了什么事情,然后就没了。

    完全没有让我想和你谈谈的理由,要知道,重要的不是你做了什么,而是你做的东西带来了什么,什么地方是只有你可以做到的,或者说你比绝大数人都做的好的。拿我自己举例,09年有幸被淘宝第一位前端小马哥以及玉伯面试过,之所以给我面试的机会,就是我的钻研精神,就这一个点,要知道我是09年才毕业的,要经验没经验,要技术没技术。所以,大家如果想寻求一份工作机会,可以 想想自己可以打动别人的亮点在哪里?

  2. 高屋建瓴的东西太多

    很多工作1~2年的小伙伴简历中充斥着Bootstrap, Vue.js, Node.js, react, H5, 工具,框架这样的字眼。这其实可以理解,很多公司hr搜简历的时候就是搜这些东西,但是,如果是给我这样技术领域的人投递简历的话,这些名词出现过多是减分的。我一直这样认为,人生职业生涯四十年,为了你之后几十年一直可以不断成长,这工作头几年重中之重一定是打好基础。否则,等到了30岁40岁,就会遇到所谓的程序员年龄天花板。为什么呢?因为盲流于技术潮流中的程序员本质上都是工具使用者,要知道使用者是具有很强的替代性的,只要文档详细,你拉一个学校里的小鲜肉他也可以用得不错,等你年纪大了,要顾家,熬不了夜,就拼不过小鲜肉,自然就会遇到所谓的年龄天花板。但是,如果你的基础很扎实,不是使用者,而是创造者,总能以不变应万变,有持续学习的能力,则越老越吃香。

    阅文这次社招不是招一个纯粹干活的,而是可以提升(或者在未来提升)整个团队文化,技术,影响力的小伙伴;需要的不是使用型前端,而是创造型前端,看重基础,而非上层。尤其那些工作经验不是很多的小伙伴,与其摆很多高屋建瓴过几年无人问津的东西,还不如好好展现自己的扎实的技术基础,语言本身的广度与深度。

好了,废话就说这么点,回到本文主体。

二、巧用浏览器CSS属性值实现向下兼容

CSS3中有很多好的特性,例如box-shadow盒阴影,但是,唯一的问题是IE8浏览器不支持,如果是对外的PC站点,则IE8浏览器不可不顾,尤其一些受众广泛的网站。

怎么办呢?我的做法往往是这样,IE9+浏览器使用box-shadow阴影,而IE7,IE8浏览器使用border线框。

例如下面截图效果:
现代浏览器使用盒阴影 IE8使用边框

也就是针对不同浏览器采取不同的策略,我们一般最先的反应是采用一些CSS hack技巧,例如,我们这里,就是要区分IE9+浏览器和IE8-浏览器,这个其实不难,可以使用:root伪类,在IE9+浏览器中,:root实际上等同于html,于是,我们都会这么做:

.box {
    border: 1px solid #ddd;
}
:root box {
    border: 0 none;
    box-shadow: 0 1px 3px rgba(0,0,0,.25);
}

从功能上满足了我们的开发需求,大多数小伙伴此时就会到此为止。实际上,我们可以做的更好。

上面这种CSS hack技巧有一个比较大的问题,就是,当我们给IE9+浏览器使用不同的CSS声明的时候,不经意间,把这些CSS声明的权重给提高了。这很容易增加我们CSS代码的复杂度,例如,经常会遇到后面样式需要覆盖前面的,由于:root .box提高了权重,我们后面样式想要覆盖,则需要更大的权重去处理,显然,代码就显得啰嗦了。

其实我们有很好的兼容区分策略,那就是充分利用浏览器对CSS属性本身的支持情况来实现浏览器的兼容区分,而不是传统的通过选择器或者一些查询语句。

就拿我们这里的盒阴影和边框例子举例,如果我来实现,则会是这样的:

.box {
    box-shadow: 0 1px 3px rgba(0,0,0,.25);
    border: 1px solid #d0d0d5;
    border: 0 rgba(0,0,0,.2);
}

想要让IE9+浏览器没有边框其实很简单,只要使用一个只有IE9+认识的同时没有边框的书写形式就可以了。虽然border所有浏览器都识别,但是rgba色值确实IE9+浏览器才支持,于是,我们就可以巧妙利用IE8-浏览器不识别rgba色值这一特性,实现我们的向下兼容处理。

由于IE8浏览器不认识rgba颜色表示,因此,在IE8眼中,下面这种写法就是不合法的,就会被忽略:

border: 0 rgba(0,0,0,.2);

这种处理技巧就是本文所要说的,利用浏览器本身的不兼容实现我们的向下兼容效果。

里面的例子,理论上,直接使用rgba(0,0,0,0)也是可以实现我们的效果的,少了1个字符,本来挺好。但是,如果你在Sass中写出border: 0 rgba(0,0,0,0);,则会被Sass自以为是地编译成border: 0 transparent,我靠,这个可就差了十万八千里了,虽然看表现rgba(0,0,0,0)transparent是一个东西,都是透明,但是,对于border属性而言,rgba(0,0,0,0) IE9+浏览器才能识别,transparent从IE7浏览器就开始识别了。于是乎,IE7,IE8浏览器下,本要出现的边框就这样直接被干掉了,妥妥的bug啊!为了规避这个让人无语的问题,这才使用了rgba(0,0,0,.2)

上面这个例子有demo,您可以狠狠地点击这里:CSS 盒阴影与边框向下兼容demo

利用类似属性值兼容性实现向下兼容的例子还有很多。

所有数值相关的兼容试试CSS3 calc()
比方说,上面IE9+去边框的例子,还可以试试这样:

.box {
    box-shadow: 0 1px 3px rgba(0,0,0,.25);
    border: 1px solid #d0d0d5;
    border: calc(0px + 0px) #000;
}

因为CSS3 calc()计算IE9+浏览器才开始支持。

背景图可是试试background多背景
这种背景图兼容处理其实非常常见,尤其你是一个喜欢SVG的小伙伴。我们可以使用SVG图形作为背景,这样retina显示屏下效果就蹭蹭蹭的好,但是,SVG有个问题,就是IE8浏览器不支持,怎么办?IE8浏览器就使用传统的图片,并且只需要1倍图就可以,对只需要1倍图,因为,我相信,这个世界是不存在哪个用户的设备是retina屏幕,但还使用IE8浏览器上网的。

下面就有个IE8浏览器向下兼容使用图片的处理问题了,大家都是背景图片,该怎么处理呢?好苦恼~~

哈哈,不要苦恼,background属性虽然都支持,但是,background的属性值和一些语法并不是所有浏览器都支持的哦,比方说多背景就是IE9浏览器才开始支持的,于是乎,我们可以这么处理:

.box {
    background: url(test.png);         /* IE8 */
    background: url(test.svg), none;   /* IE9+ */
}

基本上,以上3个属性值兼容处理就能满足大部分现代浏览器和普通浏览器的区分了。但是,上面这几个例子都是区分IE9和其他低级浏览器的,有时候,我们希望区分IE10+和其他浏览器,该怎么办呢?要知道,IE10+的选择器hack非常难搞,但是,我们却有一些属性值hack,说不定会喜出望外的好用。

区分IE10+浏览器的属性hack技巧
通过一个经典的案例说明下,大家都知道IE10+开始支持了CSS3 animation动画,于是乎,我们网页中常见的loading效果,就可以借助CSS3 animation来实现,用一个静态的png图片,使用CSS3不停地旋转,效果即达成,且效果更细腻,体积超小,而且没有白色的锯齿,可谓上上之选。

下图为传统git图和png旋转图的尺寸对比:
gif loading和png loading图片尺寸大小区别

可以看到大小完全不是一个量级的。

CSS3 animation效果虽好,但是,最大的问题在于IE9及其以下浏览器不支持。本着面向未来,尽可能让用户感受最佳体验的原则,我们会想办法采取向下兼容的实现策略,就是支持CSS3动画的浏览器CSS3实现loading效果,浏览器要是不支持,则还使用gif,于是乎,技术实现的难度变成了如何区分IE9和IE10浏览器。

要区分IE9和IE8那方法很多,因为从CSS2到CSS3是巨变,但是从IE9到IE10那是微变,所以难度不小。CSS这么语言有趣就在于,你只要足够机灵,你总可以挖掘出一些小而美的处理技巧。

哪些CSS属性IE10支持,IE9不支持了,除了transitionanimation,那就是gradient背景渐变了,于是乎,我们就可以借助多背景,巧妙实现我们的兼容效果,核心CSS代码如下:

.box {
    background: url(loading_blue.gif) no-repeat center;
    background: url(loading_blue.png) no-repeat center, linear-gradient(to top, transparent, transparent);
    animation: spin 1s linear infinite;
}

虽然IE9支持多背景,但是由于不认识渐变linear-gradient语法,所以,下面那行background:... CSS代码IE9不认识,于是,IE9就是要了上面的loading_blue.gif,从而轻松实现CSS3 animation下的loading效果的向下兼容效果。

您可以狠狠地点击这里:CSS png animation旋转向下兼容demo

Chrome浏览器下截图:
Chrome浏览器下的loading截图

需要注意的是,下面的background只能是background,虽然理论上使用background-image也是可以的,但是在IE7, IE8浏览器下面,background-image如果是个不认识的东西,他们不会认为这行CSS无效,而是认为你这个背景图有问题,于是会导致IE7,IE8浏览器下连gif loading图片都实现不出来。

如何巧妙隐藏IE9及其以下浏览器版本中的元素
最近遇到一个项目,设计师设计的一些图形效果非常适合用CSS3绘制,其中有斜纹边框效果,这就导致只能兼容到IE10,IE9及其以下浏览器还是图片。

适合图形绘制的效果截图

这个例子的HTML要比上面的loading案例要复杂,由于图形负责,因此,会有很多的HTML内容出现,而对于IE9,这些都是不需要的,因为背景图只需要一层标签即可。所以,这里出现了2处需要兼容处理的地方,其一,IE10+没有背景图;其二,IE9-里面的子元素要全部没效果,比方说隐藏。

第一个兼容处理好办,跟上面的loading处理类似:

.box {
    background: url(shape.png);
    background: linear-gradient(to top, transparent, transparent), none;
}

关键里面的元素隐藏怎么办?有什么隐藏属性IE10认识,IE9不认识的?不好意思,没有,要么都认识,要么都不认识。难道没有什么处理方法了吗?有!

我们平时写CSS3属性的时候,习惯性会加私有前缀,虽然现在很多属性都不需要了,比方说:

.box {
    -webkit-animation: spin 1s linear infinite;
    animation: spin 1s linear infinite;
}

这种私有前缀写法,本质上就是本文的利用浏览器的兼容性的向下兼容策略。所以,如果浏览器之间的属性支持有私有前缀之分,也是可以利用属性兼容性实现向下兼容效果的。

IE9和IE10之间需要私有前缀区分的CSS属性其实为数不多,其中之一就是transform属性:
IE9 transform需要私有前缀

也就是IE9浏览器下,如果transform不加私有前缀是不认识的。好了,我们有思路了,我们可以利用transform来实现我们的隐藏效果。

核心CSS如下:

.box > div {
    position: relative;
    left: -999px;                       /* 所以浏览器偏移屏幕之外 */
    transform: translateX(999px);       /* IE10+位置修正 */
}

理论上,上面代码就可以满足我们的需求了。但是,注意的是,transform需要私有前缀的浏览器是原生的IE9浏览器,用户使用的时候肯定都是使用原生版本的,如果从用户角度考虑,我们工作到此为止。但是,我们的测试同事很可能就是使用IE11等浏览器的向下兼容模式看的,要知道,IE11↘IE9的transform不需要-ms-私有前缀也能识别,很可能你这里的实现就会被报bug.
IE11的IE9浏览模式

所以,安全起见,我们需要对上面的CSS做进一步的处理,如下:

.box > div {
    position: relative;
    left: -999px;                            /* 所以浏览器偏移屏幕之外 */
    transform: translate3d(999px,0,0);       /* IE10+位置修正 */
}

嘿嘿,双保险,就算非原生IE9的transform不需要-ms-私有前缀,3d transform那肯定是不认识的,于是乎,一个完美的区分IE10和IE9隐藏的向下兼容方案就实现了。

三、对CSS属性值兼容策略技巧实现的结语

以上罗列的一些技巧仅仅是一些抛砖引玉,实际上很有很多处理技巧,主要是我只记得这么多了,等回头我想起来再补上。

有时候重要的不是技巧本身,而是解决问题的思路,以及自己的脑洞。以后,大家如果需要做一些向下兼容的处理,不妨就试试这种利用属性值兼容性实现的兼容技巧,完全不影响权重,不干扰正常的CSS复杂度。

如果你有一些不错的处理技巧,欢迎评论中反馈,我会把你的大名加到文章中,也可能会觉得这个小伙子不错,邀请你来我们这里一起实现前端梦想。

恩,要不就说这么多,再扯又要很晚睡了。

(本篇完)

分享到:


发表评论(目前31 条评论)

  1. lalala说道:

    分开来 大家可能都知道 但是如何组合成解决问题的方案 你应该也是不断的试错才成功的吧 感谢

  2. 请教了说道:

    博主什么时候写一篇文章介绍一下目前哪些css3属性可以不再需要添加私有前缀了。被这些私有前缀搞的有些晕了

  3. Trry说道:

    文章中git图是什么?是gif图吗?

  4. 小蛮腰说道:

    你的文章能让你明白做技术也是需要发散思维和清奇得得脑洞的,哈哈哈哈

  5. 大圣爱喝可乐说道:

    想看看你评论功能是怎么做的

  6. 粉丝说道:

    大侠,文章开头两点说的有道理,但是用到此文章就不好了,hack技巧就是个时代的东西,我不信5年后还在纠结ie8,9,10的问题 ,这些个东西不能算做基础!^_^

    • old man说道:

      我们公司也是支持IE6的写了无数hack,但是这的确是一个时代的产物,我觉得前端重心还是在数据交互上面。和流畅的体验。这些hack在手机端完全没用了。

  7. ###说道:

    奇银技巧,服

  8. IE8让DIV 旋转问题说道:

    前辈,能不能百忙之中抽空帮忙解决下问题:
    IE8 让DIV 旋转。IE8让IMG旋转挺方便,但是DIV我尝试了很多方法都不行。
    跪求前辈帮忙

  9. 林凡说道:

    <!–[if lt IE 7 ]&gt;&lt;![endif]–>
    <!–[if IE 7 ]&gt;&lt;![endif]–>
    <!–[if IE 8 ]&gt;&lt;![endif]–>
    <!–[if IE 9 ]&gt;&lt;![endif]–>
    <!–[if (gt IE 9)|!(IE)]&gt;&gt;–>&lt;!–

    我还是喜欢这样的方法,如果要求复杂一些就用Modernizr

  10. jessieMa1990说道:

    大神啊~好腻害,我要把文章都看完

  11. 风海流说道:

    「有什么隐藏属性IE10认识,IE9不认识的?」

    今天从前辈的一篇旧文中找到了……可以用不带前缀的 transform: scale(0)

    可惜与本文中的要求正好相反,这个是IE9-显示出来

  12. DeathGhost说道:

    不错。哈哈,时不时就记得你的博客,研究的挺细的…学习了…

  13. 夏瑜说道:

    聪明伶俐

  14. 猫哥说道:

    厉害了 word 哥,这种手法你都能想得到,脑洞开得比防空洞还大!

  15. 独自流浪说道:

    你的这些技巧,现在很多人都不懂不会~
    试试整理成这种形式?
    http://css.doyoe.com/experience/index.htm

  16. karen说道:

    每天早上上班时,都会看看有没有更新的,这次感触很深,才和别人谈论了该如果更好的学习前端,他们给我的答案是去多学学高大上的框架 插件,本人还是觉得基本拓展更重要,争取当一个创造者而不是使用者。。。。。

  17. Cshenger说道:

    我觉得算是个奇技淫巧吧,具体使用还得看情况处理

  18. GenialX说道:

    尽管本人不搞前端,但总是想来到这里瞧一瞧。不过看到这篇文章的前言讲的的确有道理,有共鸣。

  19. snadn说道:

    方法很巧,但感觉太散、不统一,不利于代码的协同和维护啊。

  20. Joe说道:

    为什么我感觉看鑫哥文章第一次都是看不懂的,难道我道行潜的原因么?

  21. 海源说道:

    666

  22. 小胡子哥说道:

    前端筑梦工程师,前来报道。

  23. yuan说道:

    color:red\9; /*IE8以及以下版本浏览器*/
    *color:green; /*IE7及其以下版本浏览器*/
    _color:purple; /*IE6浏览器*/
    经常这样用,感觉用的习惯了,这样的方法有什么缺点吗?

  24. moahmn说道:

    膜拜

  25. aBetterMan说道:

    前排感谢前辈多年的分享;
    要是能在其中学到一点处理问题的思路那就是极好的了;

  26. 风海流说道:

    使用 border 会改变元素的大小吧!IE8 兼容的时候可以考虑使用 outline

    前辈这篇文章总结得很好,这里有相关的文档 CSS Compatibility in Internet Explorer https://msdn.microsoft.com/en-us/library/hh781508(v=vs.85).aspx

    IE8- 不支持的还有某些单位 (ch, rem, vw…) 能用来作兼容

  27. notorious说道:

    跟黑客在css里xss的思路很像啊