什么是 CSS hack
在Web诞生初期,各大浏览器厂商大混战,从最初的IE和网景......到后面的Safari,Chrome,Firefox等。也因此产生了各自的Web编写规则,这已然成为了一个历史遗留问题。但不管怎样的问题,在需求下都得解决掉,于是hack就是其中一种衍变至今的方法。
由于不同厂商的流览器或某浏览器的不同版本(如IE6-IE11,Firefox/Safari/Opera/Chrome等),对CSS的支持、解析不一样,导致在不同浏览器的环境中呈现出不一致的页面展现效果。这时,我们为了获得统一的页面效果,就需要针对不同的浏览器或不同版本写特定的CSS样式,我们把这个针对不同的浏览器/不同版本写相应的CSS code的过程,叫做CSS hack。
谈一谈浏览器兼容的思路
CSS Hack大致有3种方式
-
属性前缀法(class内部Hack)
如:
- IE6识别下划线
_
和星号*
- IE7能识别星号
*
- IE6~IE10识别
\9
- Firefox对上述的都不认识。
-
选择器前缀法(即HTML条件注释Hack)
- 例如IE6能识别
*html .class{ }
- IE7能识别
*+html .class{}
或
*:first-child+html .class{}
-
条件注释法
- 针对所有IE(IE10+不再支持条件注释)
<!--[if IE]>IE浏览器显示的内容<![endif]-->
- 针对IE6以下版本
<!--[if lt IE 6]>IE6-浏览器显示的内容<![endif]-->
这类Hack不仅对CSS生效,对写在判断语句里的所有代码都会生效。
例:
.box{
color: red;
_color: blue; /*ie6*/
*color: pink; /*ie67*/
color: yellow\9; /*ie/edge 6-8*/
}
<!–-[if IE 7]>
<link rel="stylesheet" href="ie7.css" type="text/css" />
<![endif]–->
如果使用的浏览器为IE7,则会链接一个css sheet,这段代码只在IE7下可见。
IE浏览器专用的Hack方式,微软官方推荐使用的Hack方式。如下:
<!--[if IE]>
这段文字只在IE浏览器显示
<![endif]-->
只在IE6下生效
<!--[if IE 6]>
这段文字只在IE6浏览器显示
<![endif]-->
只在IE6以上版本生效
<!--[if gte IE 6]>
这段文字只在IE6以上(包括)版本IE浏览器显示
<![endif]-->
只在IE8上不生效
<!--[if ! IE 8]>
这段文字在非IE8浏览器显示
<![endif]-->
非IE浏览器生效
<!--[if !IE]>
这段文字只在非IE浏览器显示
<![endif]-->
lte:Less than or equal to(小于等于)
lt:Less than(小于)
gte:Greater than or equal to(大于等于)
gt:就是Greater than(大于)
!:不等于(取反),同javascript
CSS hack的书写顺序一般是先将适用范围广、被识别能力强的CSS定义在前面,把一些特殊的,范围小的CSS定义在后面,比如,firefox写在IE7前面,而IE7写在IE6前面以此类推。
列举5种以上浏览器兼容的写法
-
-
减号是IE6专有的hack -
\9
IE6/7/8/9/10都生效 -
\0
IE8/9/10生效,属于IE8/9/10的hack -
\9\0
只对IE9/IE10生效,是IE9/10的hack

CSS3下还有:
/*Mozilla内核浏览器:firefox3.5+*/
-moz-transform: rotate | scale | skew | translate ;
/*Webkit内核浏览器:Safari and Chrome*/
-webkit-transform: rotate | scale | skew | translate ;
/*Opera*/
-o-transform: rotate | scale | skew | translate ;
/*IE9*/
-ms-transform: rotate | scale | skew | translate ;
/*W3C标准*/
transform: rotate | scale | skew | translate ;
以下工具/名词是做什么的
-
条件注释
条件注释是一种安全的区分IE浏览器版本的语法,且被认为是取代针对IE css hack的首选办法。
IE中的条件注释(Conditional comments)对IE的版本和IE非IE有优秀的区分能力,是WEB设计中常用的hack方法。
条件注释只能用于IE5以上。
如果你安装了多个IE,条件注释将会以最高版本的IE为标准。
条件注释的基本结构和HTML的注释(<!– –>)是一样的。因此IE以外的浏览器将会把它们看作是普通的注释而完全忽略它们。
IE将会根据if条件来判断是否如解析普通的页面内容一样解析条件注释里的内容。
- 支持所有IE浏览器
<!--[if IE]>
<link rel="stylesheet" href="all-ie-only.css" type="text/css"/>
<![endif]-->
- 支持非IE浏览器
<!--[if !iE]-->
<link rel="stylesheet" href="not-ie.css" type="text/css"/>
<![endif]>
或
<!--[if !IE]><!-->
<link rel="stylesheet" type="text/css" href="not-ie.css" />
<!--<![endif]-->
- 针对IE10
!!!IE10以上不再支持条件注释,条件注释在IE10无法工作
- 针对IE9
<!--[if IE9]-->
<link rel="stylesheet" type="text/css" href="ie9.css">
<![endif]-->
- 针对IE8
<!--[if IE8]>
<link rel="stylesheet" type="text/css" href="ie8.css">
<![endif]-->
- 针对IE7
<!--[if IE7]>
<link rel="stylesheet" type="text/css" href="ie7.css">
<![endif]>
- 指定多种IE版本
<!--[if (IE 6)|(IE 7)|(IE 8)]>
<link rel="stylesheet" type="text/css" href="ie6-7-8.css">
<![endif]-->
-
IE Hack
这里的Hack并不是“骇客”的意思,旨在通过一些内部Bug和特殊方法实现,解决各品牌,版本浏览器共性不一致的方法。
Hack是不得已而为之的办法,它不是标准的,长期的,关于是否使用Hack的讨论也很多,这里不做展开。
IE下的hack包括几种:选择器hack,属性/属性值hack,媒体查询hack,js hack等。
- 选择器hack
/*IE 6*/
*html .selector {};
/*IE 7*/
.selector, {};
*:first-child+html .selector {};
*+html .selector {};
- 属性/属性值hack
/* IE6 */
.selector {
_color: blue;
}
.selector {
-color: blue;
}
/* IE6/7 */
.selector {
color: blue !ie;
}
/* string after */
/* IE6/7/8/9/10 */
.selector {
color: blue\9;
}
-
js 能力检测
问题引出:如何模拟适配各标签在不同浏览器类型、版本下的适合情况?

HTML5 shiv支持使用传统的Internet Explorer中的HTML5元素,并为IE6~IE9,Safari 4.x和Firefox 3.x提供基本的的HTML5样式。
当某一版本浏览器不支持某个元素,便可使用document.createElement()
方法来创建生成元素,便可在原生不支持的情况下使用。
问题引出:如何使不支持媒体查询功能@media {}
的IE6/7/8也能“模拟”出媒体查询的功能呢?

Bootstrap源码中也使用了respond.js,对低版本IE浏览器扩展了媒体查询功能。
其实在初学CSS时,就已经用到了css reset的思想,如
* {
margin: 0;
padding: 0;
}
这就是css reset的一种,只不过它太粗暴了。之所以需要reset,当然是因为默认提供的一些样式功能我们并不需要,甚至于,相反的,几乎所有的人都不会使用“它”,那么默认的样式就站在了前端人员的对立面,那我们肯定需要修改它了。
就比如上面的body自带的margin值。没多少人会喜欢网页边框有一条粗白线吧。
后来,在很多前端前辈的规划,完善下,就产生了很多版本,各自为营的css reset......
由于没有标准,一些开发者们也带来一些争议的问题,如:
- 性能问题
- 使用通配符存在隐性问题
- 过度的标签等于画蛇添足(那么,如何判定是否过度呢?好像也没有标准)
- 过度的标签重置导致语言元素失效
当然,问题远不止于此。
也有人提倡,css reset应该按照自己,业务的需求,适量裁剪和修改后再进行使用。
引出下面的normalize.css。
关于normalize,有人很形象的写了这么一段话:
CSS Reset 是革命党,CSS Reset 里最激进那一派提倡不管你小子有用没用,通通给我脱了那身衣服,凭什么你 body 出生就穿一圈 margin,凭什么你姓 h 的比别人吃得胖,凭什么你 ul 戴一胳膊珠子。于是 *{margin:0;} 等等运动,把人家全拍扁了。看似是众生平等了,实则是浪费了资源又占不到便宜,有求于人家的时候还得贱贱地给加回去,实在需要人家的默认样式了怎么办?人家锅都扔炉子里烧了,自己看着办吧。
Normalize.css 是改良派。他们提倡,各个元素都有其存在的道理,简单粗暴地一视同仁是不好的。body 那一圈确实挤压了页面的生存空间,那就改掉。士农工商,谁有谁的作用,给他们制定个规范,确保他们在任何浏览器里都干好自己的活儿。
个人理解:normalize就是高度定制版,普适性高的一个css reset方法。
- Preserves useful defaults, unlike many CSS resets.
保护有用的浏览器默认样式而不是完全去掉它们 - Normalizes styles for a wide range of elements
一般化的样式:为大部分HTML元素提供 - Corrects bugs and common browser inconsistencies
修复浏览器自身的bug并保证各浏览器的一致性 - Improves usability with subtle improvements
优化CSS可用性:用一些小技巧 - Explains what code does using detailed comments
解释代码:用注释和详细的文档来

Modernizr是一个JavaScript库,用于检测用户浏览器中的HTML5和CSS3功能。
详细文章
添加完Modernizr引用以后,它就立即生效了。运行的时候它会在html元素上添加一批CSS的class名称,这些class名称标记当前浏览器支持哪些特性和不支持哪些特性,支持的特性就直接显示该天特性的名称作为一个class(例如:canvas,websockets),不支持的特性显示的class是“no-特性名称”(例如:no-flexbox)。下面这段代码是运行在Chrome下的效果:
<html class=" js flexbox canvas canvastext webgl no-touch geolocation postmessage
websqldatabase indexeddb hashchange history draganddrop websockets
rgba hsla multiplebgs backgroundsize borderimage borderradius
boxshadow textshadow opacity cssanimations csscolumns cssgradients
cssreflections csstransforms csstransforms3d csstransitions fontface
generatedcontent video audio localstorage sessionstorage webworkers
applicationcache svg inlinesvg smil svgclippaths">
IE9下则是:
<html class=" js no-flexbox canvas canvastext no-webgl no-touch geolocation
postmessage no-websqldatabase no-indexeddb hashchange no-history
draganddrop no-websockets rgba hsla multiplebgs backgroundsize
no-borderimage borderradius boxshadow no-textshadow opacity
no-cssanimations no-csscolumns no-cssgradients no-cssreflections
csstransforms no-csstransforms3d no-csstransitions fontface
generatedcontent video audio localstorage sessionstorage
no-webworkers no-applicationcache svg inlinesvg smil svgclippaths">
添加完Modernizr引用以后,它就立即生效了。运行的时候首先它会在html
元素上添加一批CSS的class
名称,这些class
名称标记当前浏览器支持哪些特性和不支持哪些特性,支持的特性就直接显示该天特性的名称作为一个class
(例如:canvas,websockets
),不支持的特性显示的class
是“no-特性名称”(例如:no-flexbox
)。
你可以直接使用Modernizr在<html>元素里生成的class名称,定义相应的属性以便支持当前浏览器。如:
.boxshadow #MyContainer {
border: none;
-webkit-box-shadow: #666 1px 1px 1px;
-moz-box-shadow: #666 1px 1px 1px;
}
/*支持,则在其class下的ID内进行定义*/
.no-boxshadow #MyContainer {
border: 2px solid black;
}
/*不支持,则在其class下的ID内进行定义*/
个人理解:以支持的样式为例,由于ID名:Mycontainer是被一个class所“控制”(原谅我写不出更好的形容),即ID名在不同浏览器下是不变的,那么变化的就是判定是否支持的class名了(这由Modernizr判定更新)。当支持的样式放在不支持的浏览器上,则会是:.no-boxshadow #Mycontainer
,那就会针对性的找出.no-boxshadow
下的的样式规则。当环境变为支持时,就变为了由.boxshadow #Mycontainer
下的样式规则。我们只要事先写好不同class与ID下的规则就OK了。或者说,还是依照自己喜好命名,在默认的(比如Chrome)下就是:.abc {};
,环境变为了不支持,则:.no-abc .abc {}
下的规则即可。
PS:逻辑有点乱,还是要实战。
优点:避免了很多复写JS,if (){} else {}
这样冗余代码。
-
postCSS
PostCSS是个什么鬼东西
使用 PostCSS 进行 CSS 处理
POSTCSS
Postcss、css4带你体验一种独特的优雅
postCSS本身,可以将其理解为一个平台,一个工具,它通过JavaScript来处理CSS,使其解析抽象为语法树AST(Abstract Syntax Tree),在由插件处理。插件插件基于 CSS 代码的 AST 所能进行的操作是多种多样的,比如可以支持变量和混入(mixin),增加浏览器相关的声明前缀,或是把使用将来的 CSS 规范的样式规则转译(transpile)成当前的 CSS 规范支持的格式。
- 它能够为 CSS 提供额外的功能;
- 通过在 PostCSS 这个平台上,我们能够开发一些插件,来处理我们的CSS,比如热门的:autoprefixer>
- 我们能够使用JavaScript来开发插件(这点对前端来说很重要)
网友评论