今天我们来聊一聊如何处理CSS兼容性所带来的问题。因为浏览器厂商众多,采用的浏览器内核各不相同,所以对CSS语法支持的程度也各不相同,有的可能是语法不支持,有的可能是语法支持但是效果表现形态不同,反正都是因为浏览器不同所造成的。
要想知道各大浏览器的市场占有率是多少,可以访问百度统计网站
了解了占有率后,还要知道各个CSS样式在这些浏览器中的一个支持程度是怎样的,可以访问CANIUSE—前端兼容性自查工具或者quirksmode。
下面就来一一介绍各种CSS兼容性情况及解决手段。
直接举例,在IE10以下的浏览器中,给图片添加链接,默认会产生一个蓝色的边框,而高级浏览器却没有这个现象,所以需要给img{ border-style: none; }
来解决这个CSS兼容性问题。
这种类似的问题非常多,幸好有一个专门的库,可以解决大部分这样的兼容性问题,即:Normalize CSS。Normalize CSS可以看成是一种Reset CSS的替代方案。创造Normalize CSS有下面这几个目的:
所以强烈建议在开发网页的时候,首先要引入Normalize CSS然后再进行具体的样式编写。
有时候浏览器的默认行为可通过添加浏览器前缀的方式进行解决。先来了解下什么是浏览器前缀,我们都知道一个CSS样式从提案到正式发布是需要漫长时间的,而浏览器厂商为了提前满足市场需求,就通过添加浏览器前缀的方式提前去支持这些样式,这样等样式正式发布的时候,也不影响正常的使用。常见的浏览器前缀有:Chrome和Safari的-webkit-、Firefox的-moz-、IE的-ms-等。
比如在IOS下,切换横屏的时候字体会自动变大,可以通过给html{ -webkit-text-size-adjust: 100%; }
来解决这个问题。再比如输入框在IE下会有一个关闭的✖号,可以通过给input[type=text]::-ms-clear{ display: none; }
来解决这个问题。
有时候不同浏览器下的默认样式是没办法统一的,例如表单的一些元素,如:复选框、单选框、下拉菜单等,这时就需要完全模拟样式才能解决,下面是模拟的复选框实现方案代码:
<style> .checkbox{ width: 20px; height: 20px; display: inline-block; overflow: hidden; } .checkbox input{ display: none; } .checkbox div{ width: 100%; height: 100%; border: 1px #767676 solid; border-radius: 2px; box-sizing: border-box; } .checkbox input:checked + div{ background: #0075ff; display: flex; } .checkbox input:checked + div::after{ content: ""; margin: auto; width: 10px; height: 4px; border:1px white solid; border-top:none; border-right:none; transform: rotate(-45deg); position: relative; top: -2px; } </style> <body> <label class="checkbox"> <input type="checkbox"> <div></div> </label> </body>
有时候我们需要为不同的浏览器甚至不同版本编写特定的 CSS样式,这个过程被称为 CSS hack!CSS hack的书写方法大致可归纳为以下几种:条件hack,属性hack,选择器hack。
条件hack 是 HTML 源码中被 IE 有条件解释的语句。条件hack可被用来向 IE 提供及隐藏代码。使用了条件hack的页面在 IE9 中可正常工作,但在 IE10 中无法正常工作,IE10不再支持条件hack。
<!--[if IE 8]> <link href="ie8only.css" rel="stylesheet"> <![endif]-->
语法 | 案例 | 说明 |
---|---|---|
! | [if !IE] | 非IE |
lt | [if lt IE 5.5] | 小于IE5.5 |
lte | [if lte IE 6] | 小于等于IE6 |
gt | [if gt IE 5] | 大于IE5 |
gte | [if gte IE 7] | 大于等于IE7 |
\ | [if (IE 6)(IE 7)] | IE6或IE7 |
属性hack:在CSS样式属性名称前面加上一些hack前缀,这只能被特定的浏览器识别。
_
:选择IE6或更低。此外,还可以使用连线(中划线)(-),以避免与某些划线的属性相混淆,因此最好使用下划线(_)*
:选择IE7或更低。例如:(+)和(#)等,虽然行业对(*)的认知程度较高\9
:选择IE6+\0
:选择IE8+和Opera15以下的浏览器.box{ color: #090\9; /* IE8+ */ *color: #f00; /* IE7 */ _color: #ff0; /* IE6 */ }
选择器hack:对于网页表现不一致或需要特别对待的浏览器,在CSS选择器之前加上一些前缀,只有特定的浏览器才能识别。
* html .box { color: #090; } /* For IE6 */ * + html .box { color: #ff0; } /* For IE7 */
渐进增强是针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验
优雅降级是一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
举例说明,比如在高级浏览器中支持边框圆角(border-radius),而低版本浏览器不支持边框圆角,这时采用直角方式,这就是优雅降级,当然也可以采用图片模拟圆角的形式,也是属于优雅降级。再比如高级浏览器支持阴影(box-shadow),而低版本浏览器不支持阴影,这时只是采用普通的边框代替,属于优雅降级。
简单来说,低版本浏览器的主要功能不受影响,布局没有严重的错乱问题即可。不用非要跟高级浏览器完全一致,这种思想便是优雅降级。一般可采用样式是否支持来进行覆盖操作,具体举例代码如下:
<style> .box { width: 200px; height: 200px; box-shadow: 0 1px 3px rgba(0,0,0,.25); border: 1px solid #d0d0d5; border: 0 rgba(0,0,0,.2); } </style> <body> <div class="box"></div> </body>
由于IE8浏览器不认识rgba颜色表示,因此,在IE8眼中,border: 0 rgba(0,0,0,.2);
这种写法就是不合法的,就会被忽略。
Polyfill 是一块代码(通常是 Web 上的 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。简单来说就是通过JavaScript方式来解决CSS兼容性问题,通常需要引入一个JavaScript文件。
下面介绍一些常见的处理CSS兼容性的Polyfill:
这里我们只举一个例子,举一反三就可以了,Respond.js是让让IE6-8支持媒体查询,首先先去下载相关的JS文件,可以通过github进行下载,即:respond.src.js文件
Respond.js在使用的时候,有一些要求,需要启动本地服务器(localhost),不能使用普通本地的url地址(file://开头);需要外部引入CSS文件,将CSS样式书写在style中是无效的;由于respond插件是查找CSS文件,再进行处理,所以respond文件一定要放置在CSS文件的后面。
<style> .box{ width: 100px; height: 100px; background: pink; } </style> <link rel="stylesheet" href="./test.css" media="screen and (max-width: 480px)"> <script src="./respond.src.js"></script> </head> <body> <div class="box"></div> </body>
/* test.css */ .box{ background: skyblue; }
前面介绍过的一些解决方案,像添加浏览器前缀,优雅降级,JavaScript处理CSS兼容等等,一般都需要手动去完成,而postcss是一种工程化的方式去解决这些兼容性,从而达到自动化的处理。
PostCSS 是一个允许使用 JS 插件转换样式的工具。 这些插件可以检查(lint)你的 CSS,支持 CSS Variables 和 Mixins, 编译尚未被浏览器广泛支持的先进的 CSS 语法,内联图片,以及其它很多优秀的功能。
常见的利用postcss来解决CSS兼容性的插件非常多,这里介绍一些:
这里我们只举一个例子,举一反三就可以了,postcss-cssnext能够让CSS高级新语法得到支持,原理就是对于不支持新语法的浏览器进行语法降级处理。
postcss可以在前端工具webpack、gulp中进行集成,也可以单独通过nodejs环境进行使用。
const cssnext = require('postcss-cssnext'); module.exports = { plugins: [ cssnext ] };
/* src/demo.css */ :root{ --color: pink; } .box{ color: var(--color); background-color: var(--color); border: 1px var(--color) solid; }
postcss src/demo.css -o dist/demo.css -w
/* dist/demo.css */ .box{ color: pink; background-color: pink; border: 1px pink solid; }
移动端的CSS兼容性还是蛮多的,这里给大家列举一些常见的兼容处理,首先就是移动端1px的问题。要了解这个问题,首先需要了解什么是逻辑像素和物理像素。
逻辑像素,也叫“设备独立像素”,对于前端来说就是css中的像素,举例:iphone6下的逻辑像素为375px。
物理像素,即设备屏幕实际拥有的像素点,一个设备生产出来,他们的像素就已经确定了,举例:iphone6下的物理像素为750px。
可以发现iphone6下,其物理像素是逻辑像素的2倍,可用“设备像素比”来表示这个比值(即物理像素除以逻辑像素的值),可通过JavaScript代码window.devicePixelRatio
来获取设备像素比。
那究竟逻辑像素与物理像素的关系是什么呢?这里首先先确定什么是相对单位,什么又是绝对单位。像m这种绝对单位,定义是什么:米的长度等于氪-86原子的2P10和5d1能级之间跃迁的辐射在真空中波长的1650763.73倍。查到的m的定义如上,也就是说在现实世界中,m是一个固定的长度。
px全称为pixel,像素长度,像素长度,那么就请问了,一个超大屏幕的像素和你笔记本或者手机屏幕的像素大小相同吗?也就是说1px在你手机屏幕上显示出来的长度可能为0.1mm,在露天演出的电子屏幕上长度为5cm,那么0.1mm和5cm相等吗?
感觉px好像是一个相对单位,但是如果放在网页或者设计人眼中,可能就不一定了,上面举得那个例子是物理像素,在物理像素的背景下,px确实是一个相对单位,但是在逻辑像素上就不同了,css中1px指的是逻辑像素,浏览器会将你的逻辑像素转化成物理像素,每个设备之间虽然物理像素点大小不一样,但是用例逻辑像素的单位后,显示的长度就会一样了。
在开发网页的时候,写了10px,在你的设备上,逻辑1px为真实的1.2个像素大小,实际看上去为10cm,没问题,换一个设备,逻辑1px为真实的2.4个像素大小,也就是说另外一个设备像素大小是你的设备一半,那么对于他来说10px就是24个像素了,但是实际大小仍然为10cm,所以说,在有逻辑像素的概念的前提下,px是一个绝对长度单位。
总结如下:
- 逻辑像素:CSS中的像素,绝对单位,保证不同设备下元素的尺寸是相同的。
- 物理像素:设备屏幕实际拥有的像素点,相对单位,不同设备下物理像素大小不同。
通常移动端UI设计稿会按照iphone6的物理像素尺寸大小进行设计,即750px。当然也可以按照逻辑像素进行设计,即375px,但是一般设计师不会这么干,主要为了设计稿更加清晰。
所以前端在量取尺寸的时候,需要除以2,才能适配页面中的CSS逻辑像素值。好在现代UI工具如:蓝湖、PxCook等都具备自动除以2的标注信息方式。
这样当设计稿上的像素设置1px的时候,那么对应的逻辑像素就应该是0.5px,那么0.5px在新版浏览器中是支持的,所以我们这样写样式border:0.5px gray solid
是没有任何问题的,而在旧版浏览器中要做到兼容处理,就需要采用 transform:scale(0.5)的方式了。