一.作用
与media query(媒体查询)类似,feature query(特性查询)也是一种条件样式,仅在支持特定样式规则的环境应用指定的一组样式:
等等,这种能力似乎CSS生来就有:
为了保证新属性和新值将来可以添在现有的属性上,用户代理必须忽略一份非法样式表的某一部分,如含有未知属性的声明、含有非法值的声明、含有未知@关键字的@规则等等。
P.S.具体见4.2 处理解析错误的规则
CSS从设计之初就是容错的,当前环境下支持的样式规则会被正确应用,不支持的会被静默忽略掉:
比如经常见到的:
我们知道在支持box-shadow的环境下会呈现阴影,使之看起来像是一张悬浮的卡片,在不支持的环境则只剩下外边距与边框,变成扁平的普通矩形块,算是天然的样式降级。这种包容能力,让新特性的应用少了一些忧虑(大不了不支持,回到降级方案)
那么,feature query带来了什么能力?
相当于内置了友好的渐进增强机制,之前通常用Modernizr来做的事情,现在多了一种选择,比如:
与之前的区别在于,就影响范围而言,容错降级只会影响应用了这些不支持样式的元素,而特性查询降级能够影响一组任意元素,例如:
P.S.严格地讲,容错降级一般是声明级的(一些声明被忽略或应用),而特性查询降级是规则集级的(一些规则集被忽略或应用):
声明要么为空要么由一个后面跟着冒号(:)和属性值的属性名组成,之间可以有空白字符
规则集(也叫“规则”),由后面跟着一个声明块的选择器组成
二.语法
语法层面,feature query称为@supports CSS at-rule,与media query对比如下:
长得很像,都表示@关键字后面的条件成立时,应用{...}里的样式规则。二者都是条件分组规则(conditional group rules):
另外,条件部分支持与(and)或(or)非(not)逻辑运算:
P.S.仅支持属性名-值对儿形式的条件,不支持其它形式的,比如:
三.用法
实际场景中,一般模式(最佳实践)为:
需要注意的是,不支持某特性并不等价于否定形式的feature query(@supports not):
无法如预期地筛选出不支持vh的环境,因为如果连@supports都不支持,整个@规则都会被忽略,包括这组降级样式。也就是说,这个判断不可靠,会漏掉一部分(既不支持@supports也不支持vh的环境)
同样,肯定形式的feature query也不是完全可靠的,例如:
在不支持@supports但支持vh的环境,就不符合预期。但这通常不足为虑,因为一般需要判断支持性的特性比feature query更前沿一些
四.优雅降级与渐进增强
针对浏览器不一致的问题,这是两种类似的应对策略,区别在于:
优雅降级:高端环境优先,妥协让步低端环境(特效全开,低端环境进行特效降级,底线是保证可用)
渐进增强:低端环境优先,特殊照顾高端环境(先保证可用的底线,再考虑加特技)
Modernizer
Modernizr,一般特性检测方案,通过JS来检查运行环境是否支持指定特性:
简言之,Modernizr有助于区分高端与低端环境,这样就允许我们针对低端环境进行降级(fallback),或者打补丁(polyfill)。例如:
作为一种JS方案,优势是足够灵活,不仅支持查询CSS特性,还支持所有可以通过JS检测的特性,例如:
但存在几个问题:
性能:需要引入额外JS,需检测的新特性会越来越多,体积势必越来越大,存在性能负担
扩展性:依赖第三方支持,最新的特性可能需要等待一段时间才有对应的特性检测,相当于(更新Modernizr版本)手动扩展
易用程度:通过查表得到目标特性的名称(如batteryapi、flexbox等,更多名称见Features detected by Modernizr)后,才能检查该特性,不很方便
特性粒度:以上面提到的特性名称为最小检测单元,并不一定合适,比如justify-content: space-evenly可能没有与之对应的特性名称
可靠性:依靠辅助手段来检测特性支持性,并不百分百靠谱,比如部分实现的版本,可能无法准确区分出来
CSS Feature Query
浏览器内置的CSS特性检测支持。是否支持某样式规则,最清楚这件事的当然是浏览器自己,只是这次通过feature query把这种内部状态暴露出来了而已
对比Modernizer,有几个优势:
性能更优:纯CSS方案,不需要JS参与
扩展性良好:作为浏览器的基础能力,任意新特性发布后都立即可检测,不需要手动扩展
语法自然:以样式声明作为查询条件,而不需要查表获得特性名
细粒度:属性名-值对儿粒度,足够灵活
可靠:支持不支持是浏览器自己说的,绝对靠谱
当然,缺点是只支持样式特性查询,对于非CSS特性则无能为力。所以就功能而言,Modernizer是CSS feature query的超集
五.兼容性
桌面:Firefox、Chrome、[Safari 9+]、[Edge 12+]([IE 11-]都不支持)
移动:[iOS 9.0+]、[Android 4.4+]
P.S.具体见Can I use
移动端基本可以放心使用了,即便不支持@supports,也没有实质影响(只是会忽略这组样式,与低端环境的表现一致)
特殊的,需要注意几点:
feature query无助于识别存在bug的特性实现,与某些不完整的特性实现(比如不支持某种机制,但无法从属性名/值上区分出来)
feature query特性自身的兼容性问题会导致某些场景不符合预期(比如支持某特性,却由于不支持@supports而被忽略掉了),但不会造成严重影响
一个典型的例子是Safari 8支持flexbox,但不支持feature query,就会出现bad case:
例如:
在Safari 8下就呈现降级样式了,虽然它支持flexbox
六.应用场景
就应用场景而言,feature query用来解决新特性兼容性方面的忧虑,作为渐进增强的一种手段,一般用法:
渐进增强,意味着要接受多环境下的不一致。实际上,对于阴影、圆角、动画之类的很容易接受这种不一致(在不友好的环境去掉这些锦上添花的效果),而对于flexbox、grid等布局方案,似乎很难与渐进增强联系起来,因为布局通常是不可或缺的,而不只是锦上添花
渐进使用grid特性
Is There A CSS Grid Polyfill?
尽管很遗憾,但grid布局确实没有CSS polyfill。那么,非得等到多年以后才能使用这个强大的特性吗?
当然不是。至少有两种选择:
渐进地(仅在支持的环境)使用grid特性(即接受不同环境下的布局存在差异)
JS补丁方案没什么好说的,对于渐进方案,关键在于接受这种差异:
把布局效果也当做一种增强样式(像阴影、圆角等效果一样),允许在低端环境展示另一种不同的降级(布局)效果。例如:
对应样式为:
(摘自display: feature queries demo)
在支持Grid的环境下,呈现为漂亮的泾渭分明的3列等比布局,在不支持的环境,降级到稍显拥挤的float布局:

grid-layout-css-polyfill
差强人意,但在不改变结构、不借助JS的前提下,float方案差不多只能做到这种程度了。如果能够接受类似差异的话,通过feature query渐进使用,新特性的兼容问题将不再重要
检查是否支持自定义属性
利用CSS变量,很容易把换肤功能作为一种增强效果来提供
首字母下沉效果
在支持initial-letter的环境(如Safari)很容易实现这种常见的排版效果(段落首字母下沉4行):
不支持的话,用常规方式来实现:
P.S.更多案例见参考资料中feature query相关的,如mix-blend-mode等
参考资料
@supports
Using Feature Queries in CSS
How to use CSS Feature Queries
Using CSS Grid: Supporting Browsers Without Grid
Basic grid layout with fallbacks using feature queries