什么是CSS特征检测?我们知道,在前端技术飞速发展的今天,各种新技术、新属性层出不穷。这在CSS级别也不例外。一些新的属性可以极大的提升用户体验,减少工程师的工作量,而且在现在的前端风气下:很多实验性的功能还没有成为标准却被广泛使用;它们需要兼容多种终端和浏览器,而每个浏览器兼容一个新功能的实现性能有很大差异;因此,有优雅的退化和渐进的增强。在这样的背景下,想用新技术为用户提供更好的体验,想做好回归机制,保证低版本终端用户的基本体验,CSS特征检测应运而生。CSS特征检测是针对不同的浏览器终端,判断当前浏览器是否支持某种特征。使用CSS特征检测,我们可以在支持当前特征的浏览器环境中使用新技术,并对不支持的浏览器环境做一些回退机制。本文将主要介绍两种CSS特征检测的方法:@supportsmodernizrCSS@supports传统的CSS特征检测是通过javascript实现的,但未来可以实现原生CSS。CSS@supports通过CSS语法实现特征检测,在内部CSS块中写入特征检测通过后期望实现的CSS语句。语法:@supports{/*specificrules*/}例如:div{position:fixed;}@supports(position:sticky){div{position:sticky;}}在上面的例子中,position:sticky是Aposition的新属性用于实现粘性布局,可以轻松实现一些以前需要javascript才能实现的布局(详情点我[1]),但目前只在-webkit-内核下支持。上面的写法首先定义了div的position:fixed,然后下面这句@supports(position:sticky)就是特征检测括号中的内容。如果当前浏览器支持@supports语法和position:sticky语法,那么div将被设置为position:sticky。我们可以看到@supports的语法核心就在于这句话:@supports(...){},括号里面是一个CSS表达式,如果浏览器判断括号里面的表达式是合法的,那么它将转至在括号内呈现CSS表达式。除了这个最常见的用法之外,它还可以与其他几个关键字一起使用:@supportsnot&&@supportsand&&@supportsor@supportsnot——非非运算符可以放在任何表达式前面以生成一个newexpression,新表达式是对原表达式值的否定。看一个例子:@supportsnot(background:linear-gradient(90deg,red,yellow)){div{background:red;}}因为加了not关键字,所以和上面第一个例子相反。如果浏览器不支持线性渐变背景的语法:linear-gradient(90deg,red,yellow),则设置div的颜色为redbackground:red。@supportsand--这个也很好理解,多重判断,类似于javascript的&&运算符。使用and运算符连接两个原始表达式。仅当两个原始表达式的计算结果都为真时,结果表达式才为真,否则为假。当然,也可以连接任意数量的表达式,看例子:p{overflow:hidden;text-overflow:ellipsis;}@supports(display:-webkit-box)and(-webkit-line-clamp:2)and(-webkit-box-orient:vertical){p{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;}}同时检测@supports(display:-webkit-box)和(-webkit-line-clamp:2)和(-webkit-box-orient:vertical)提供三种语法,如果同时支持,设置三种CSS规则。这三种语法必须同时被浏览器支持。如果表达式为真,可以用它来实现多行省略的效果:代码演示-@supportAnd[2]@supportsor--或者理解@supportsand,很容易理解@supportsor,类似于javascript的||运算符,只要其中一个表达式为真,则生成的表达式表达式为真。参见示例:@supports(background:-webkit-linear-gradient(0deg,yellow,red))or(background:linear-gradient(90deg,yellow,red)){div{background:-webkit-linear-gradient(0deg),yellow,red);background:linear-gradient(90deg,yellow,red)}}上例中只检测浏览器支持background:-webkit-linear-gradient(0deg,yellow,red)or(or)之一background:linear-gradient(90deg,yellow,red)为div元素添加渐变。CodePenDemo--@supportsor[3]当然关键字not也可以和andoror混用。有兴趣的可以试试。我可以用吗?兼容性方面先看Caniuse(更新到2021/05/13)[4]:Caniuse--CSS@support大部分浏览器都已经支持了,主要是需要用polyfill来兼容Android4.4以下版本。我们准备好了,使用@supports来实现渐进增强。渐进增强:为低版本浏览器构建页面,保证最基本的功能,然后为高级浏览器改进和添加效果、交互等功能,以达到更好的用户体验:说到CSS.supports()时@supports,有必要说说CSS.supports()。它作为@supports的另一种形式出现,我们可以使用javascript来获取CSS属性的支持。可以打开控制台输入CSS.supports试试:如果你自己没有实现CSS.supports的方法,输出以上信息,说明浏览器支持@supports的语法,按如下方式使用:CSS。supports('display','flex')//trueCSS.supports('position','sticky')//true,有什么用呢?如果你的页面需要动态添加一些你不确定哪些浏览器支持的新属性,那么它可能会派上用场。并且,它可以与我们将在下面讨论的modernizr合作。上面modernizr介绍了CSS方法的特征检测。以前,特征检测通常使用javascript,其中modernizr最为突出。modernizr(戳我查看Github[5])是一个开源的javascript库。一星近2W,其优秀可见一斑。简单看一下使用方法,假设页面已经引用了modernizr,语法如下://Listentoatest,giveitacallbackModernizr.on('testname',function(result){if(result){console.log('Thetestpassed!');}else{console.log('Thetestfailed!');}});//或类似CSS.supports()Modernizr.testAllProps('background','linear-gradient(90deg,#888,#ccc)');//true举一个实际的例子,假设我们想在支持渐变样式的浏览器中对一个div进行不同的处理,使用如下CSS:div{background:#aaa;}.linear-gradientdiv{background:linear-gradient(90deg,#888,#ccc);}使用Modernizr判断,如果支持渐变,在根元素上添加.linear-gradient样式,方便例如使用jquery语法:if(Modernizr.testAllProps('background','linear-gradient(90deg,#888,#ccc)')){$('html').addClass('linear-gradient');}Demo-modernizr[6]当然,Modernizr有还有很多其他的功能,你可以去看看它的API。特性检测原理如果觉得Modernizr整个库的引入太大,页面不支持@supports,其实我们用简单的javascript实现就很方便简单了。如果想知道浏览器支持多少个CSS属性,可以在调试窗口试试:varroot=document.documentElement;//HTMLfor(varkeyinroot.style){console.log(key);}上面的截图只是一个小的打印部分。如果我们要查看某个属性样式是否被支持,我们可以查看它是否存在于任意element.style中,即上面代码示例的root可以替换为任意元素。当然,元素可能有背景属性,但不支持特定的linear-gradinet()属性值。这时候怎么检测呢?你只需要给一个元素赋一个特定的值,然后检查这个属性值是否可以被读取。varroot=document.documentElement;root.style.backgroundImage='linear-gradient(90deg,#888,#ccc)';if(root.style.backgroundImage){//support}else{//notsupported}所以上面Modernizr中的例子,javascript代码可以改成:varroot=document.documentElement;root.style.backgroundImage='linear-gradient(90deg,#888,#ccc)';if(root.style.backgroundImage){$('html').addClass('linear-gradient');}当然在判断这个具体的属性值的时候有CSS赋值操作,所以我们选择判断的元素应该是隐藏在页面上的元素。各种方法的优缺点原生@supports的性能肯定是最好的,不需要引入外部javascript。这是首选,但由于兼容性问题,目前不是最佳选择。Modernizr功能强大,兼容性好,但需要引入外部javascript和多一个http请求。如果只做少量的特征检测,感觉就像是杀鸡用牛刀。对于需要的特征检测,使用javascript实现一个简单的功能,然后封装上面使用的方法:/***对于简单的CSS特征检测*@param[String]property要检测的CSS属性名称*@具体属性valueofparam[String]valuestyle*@return[Boolean]是否通过校验*/functioncssTest(property,value){//用于测试的元素,页面隐藏varele=document.getElementById('test-display-none');//只有一个参数if(arguments.length===1){if(propertyinele.style){returntrue;}//两个参数}elseif(arguments.length===2){ele.style[property]=value;if(ele.style[property]){returntrue;}}returnfalse;}软件工程没有灵丹妙药,所以无论哪种方式,都有适合的场景,我们要做的就是掌握和理解它们的原理,根据不同的场景灵活运用。最后,本文到此结束,希望对你有所帮助:参考[1]详情戳我:http://www.cnblogs.com/coco1s/p/6402723.htm[2]CodeDemo-@supportAnd:http://codepen.io/Chokcoco/pen/EWjbpv?editors=1100[3]CodePenDemo--@supportsor:http://codepen.io/Chokcoco/pen/yMNvvZ[4]我可以吗使用(更新至2021/05/13):http://caniuse.com/#search=%40supports[5]戳我查看Github:https://github.com/Modernizr/Modernizr[6]Demo-modernizr:http://codepen.io/Chokcoco/pen/oZjNjW[7]Github--iCSS:https://github.com/chokcoco/iCSS