前端开发工程师的心中一直萦绕着这样一个问题:这么写可以吗。判断CSS支持哪些浏览器,在不支持的浏览器中优雅降级,这些工作几乎占用了开发的大部分时间。像Modernizr这样的特性检测工具很大程度上帮助解决了这样的问题,但是不是所有的情况都适用,而且会加载很多我们不需要的Javascript。
理想状态下,我们需要一个原生方法帮助我们检测浏览器中支持的CSS,并让我们直接找到这些特性,其实我们可以通过@supports
和Javascript的CSS.support()
方法来实现这个目标。在本文中,我会说明一下这个属性的CSS规范,包括不支持浏览器中的Javascript方案。
特性检测语句
作为@
规则,@supports
的书写方式跟@mediaqueries
一样,可以把它想成是一种CSS形式的if
声明。例如,我们要检测浏览器是否支持vw
单位:
@supports ( width: 75vw ) {
/* 支持vw单位浏览器的CSS规则 */
}
注意圆括号中的条件必须以有效CSSproperty: value
的形式书写,@supports (vw) { }
这样写是无效的。你也可以使用or
语句,在检测带有浏览器前缀属性的时候会很有帮助:
@supports ( display: -webkit-flex ) or ( display: -ms-flex ) or ( display: flex )
{
/* 支持flexbox浏览器的代码 */
}
你也可以使用and
来添加条件,例如,可以使用以下语句来检测浏览器是否同时支持CSS的currentColor和HSL color属性:
@supports ( color: currentColor ) and ( color: hsl(0,50%,30%) {
/* 支持currentColor和HSL浏览器的代码 */
}
再次重申,书写什么CSS代码并不重要,只要代码有效就行。最后——也可能是最没用的——条件:not
语句:
@supports not (display: inline-grid) {
/* 不支持CSS grid浏览器的代码 */
}
and
、or
和not
可以混合使用以应对复杂情况。
支持情况
现在Firefox、Chrome、Android(4.4+)和Opera支持@supports
,Safari和IE还不支持,这样会导致一个矛盾:@supports
仅在支持的浏览器中才会有效,其他的无效。这句话其实不完全对,我们一会儿会说到。
在不支持的浏览器中使用@supports
我们其实可以在不支持CSS规则或Javascript方法的浏览器中间接使用@supports
,我写过一篇关于使用Open Type实现真正的小型大写的文章,其中一条评论提出了使用@supports
解决问题的例子:我们不能同时使用font-variant: small-cap
和OpenType,这意味着那些不支持OpenType的浏览器会显示小写的文本,这个问题可以使用@supports
方法解决,这种解决方案让我想起了我最近写的一篇文章用CSS媒体查询触发Javascript:
@font-face {
font-family: Questa Grande;
src: url(Questa_Grande_Regular.otf) ;
}
p { font-family: Questa Grande, sans-serif; font-size: 2rem; }
@supports ( -moz-font-feature-settings: "smcp=1" )
or ( -moz-font-feature-settings: "smcp" )
or ( -ms-font-feature-settings: "smcp" )
or ( -o-font-feature-settings: "smcp" )
or ( -webkit-font-feature-settings: "smcp" )
or ( font-feature-settings:"smcp") {
p:first-of-type:first-line {
-moz-font-feature-settings: "smcp=1";
-moz-font-feature-settings: "smcp";
-ms-font-feature-settings: "smcp";
-o-font-feature-settings: "smcp";
-webkit-font-feature-settings: "smcp";
font-feature-settings:"smcp";
}
body:before { content: 'small-caps'; display: none; }
}
这段代码的意思是:如果浏览器支持OpenType,那么在第一个段落的第一行执行小型大写样式,然后为<body>
的伪元素添加small-caps
的文本并隐藏。这其实是我们给Javascript的一个“信息”:
var smallcaps = window.getComputedStyle(document.body, ':before' ).content;
if (smallcaps!== "small-caps") {
var css = document.createElement('style');
var styles = 'p:first-of-type:first-line { font-variant: small-caps }';
if (css.styleSheet)
{ css.styleSheet.cssText = styles; }
else {
css.appendChild(document.createTextNode(styles))
}
document.getElementsByTagName("head")[0].appendChild(css);
}
这段脚本会查找隐藏的文本:如果没有找到,脚本会为段落创建一个回退,并应用在<head>
标签中,这样在不支持OpenType的浏览器中也能实现首行小型大写了。
效果如下:
总结
虽然使用@supports
还有争议,但在这篇文章中,我展示了让每个浏览器都能使用的方法:你可以在<body>
的伪元素里面添加文本让Javascript检测,或者运用多重样式名代表你想要测试的特性,就像Modernizr这样,不过我们使用的是原生Javascript和CSS。
来源:前端观察