说说CSS中的@supports

发布于 大漠

CSS中的@supports属性已经不是新东西了,只不过一直以来,大家碍于浏览器对其支持度不强,而无人问冿。这两天看到两篇新文单都是介绍@supports。其中一篇是介绍怎么使用@supports来查询CSS的新特性,另外一篇是如何使用@supports来改变你的生活。

今天也继续来说说这个@supports属性。

@supports是什么

@supportsCSS条件查询规范CSS3 Conditional Rules Specification)中属性之一,CSS中条件查询除了今天要说的@supports之外,还有大家较为熟悉的媒体查询@media)和@viewport

@supports作用是什么

@Abbey Fitzgerald的《How to use CSS Feature Queries》一文的标题来看,就大概知道@supports是用来查询CSS的新特性的。那么查询CSS的新特性有什么用处呢?或许你知道新出现的CSS特性,但又担心浏览器不支持,从而又不敢使用。很多时候就算是使用了CSS的新特,达到自己需要的效果,但为了让自己的项目给用户带来更好的体验,希望在一些不支持新特性的浏览器做一些降级方案。那么这个时候@supports功效或者说作用就出来了。

从这一点而言,CSS的@supports作用就是用来查询浏览器是否支持CSS的特性

对于Web前端开发的同学,对Modernizr这个JavaScript库并不会陌生,一直以来都是依赖于这个库帮助大家做一些降级处理。那么有了CSS的@supports,将可以抛弃这个JavaScript库。先来简单的看看一个小示例:

body {
    width: 100vw;
    height: 100vh;
    background-blend-mode: hue;
    background-image:linear-gradient(to right, rgb(166, 80, 80), rgb(139, 0, 0)), url(//c8.staticflickr.com/4/3654/3485478215_19a06ca23c_b.jpg);
    background-repeat:repeat, no-repeat;
    background-position: center;
    background-size: cover;
}

早期,我们依赖Modernizr库,需要这样处理:

.no-background-blend-mode {
    background-image:url(//c8.staticflickr.com/4/3654/3485478215_19a06ca23c_b.jpg);
}

而现在,我们只需要这样做即可:

body {
    width: 100vw;
    height: 100vh;
    background: url(//c8.staticflickr.com/4/3654/3485478215_19a06ca23c_b.jpg) no-repeat center;
    background-size: cover;
}
@supports (background-blend-mode: hue) {
  body {
    background-blend-mode: hue;
    background-image:linear-gradient(to right, rgb(166, 80, 80), rgb(139, 0, 0)), url(//c8.staticflickr.com/4/3654/3485478215_19a06ca23c_b.jpg);
  }
}

对于支持 CSS的background-blend-mode属性的Firefox和Chrome浏览器,你可以看到上面的效果,而对于不支持的Safari浏览器,你看到的效果如下图看示:

supports

上面简单的示例,再次证明CSS的@supports能帮助浏览器很好的检测是否支持CSS的属性,而且能更好的帮助我们对自己的效果做优雅的降级处理。

@supports的兼容性

当你看到这里的时候,你或许会担心。@supports也是CSS的新特性,如果浏览器对这个属性不支持的话,上面的一切都是空谈了吗?原则上是这样的,但值得庆幸的时,到目前为止,现代浏览器除了IE系列之外,都对@supports有很强的支持性,甚至在移动设备上支持度也非常的好。

如何使用@supports

对于@supports的使用,其实很简单,早期在《CSS3条件判断:@supports》一文中有详细的介绍怎么使用@supports。这里简单的回顾一下怎么使用。

最常见的方式:

@supports (property: value) {
  element {
    property: value;
  }
}

基中property: value@supports用来判断的条件语块。如果浏览器支持property: value,将会返回true,也就是说浏览器将会渲染element {property:value} 样式块,如果不支持,则会返回false,将不会渲染这里的样式。当然对于不支持条件语块,还可以通过 not()语块来执行:

@supports not (property: value) {
  element {
    property: value;
  }
}

来看一个简单示例:

<article class="artwork">
  <img src="myimg.jpg" alt="cityscape">
</article>

结构很简单,主要来看下面这段CSS:

@supports (mix-blend-mode: overlay) {
  .artwork img {
    mix-blend-mode: overlay;
  }
}

@supports not(mix-blend-mode: overlay) {
  .artwork img {
    opacity: 0.5;
  }
}

上面的示例是说,如果浏览器支持mix-blend-mode:overlay,将会执行@supports (){...},如果不支持则会执行@supports not() {...}。支持的浏览器能看到的效果如下:

不支持的浏览器,看到的效果则是图片有50%的透明度。

另外,在使用@supports时,条件语句块一定要放到()里面,如果不放在这里面的话,将会失效(错语语法)。比如:

// 无效的@supports写法
@supports mix-blend-mode:overlay {
    .artwork img {
        mix-blend-mode: overlay;
    }
}
    
// 有效的@supports写法
@supports (mix-blend-mode:overlay) {
    .artwork img {
        mix-blend-mode: overlay;
    }
}

上面的示例展示的都是单个条件块的,其实还可以支持多个条件块。它支持与(and)、或(or)和非(not):

and

@supports (property1: value1) and (property2: value2) {
  element {
    property1: value1;
    property2: value2;
  }
}

条件都成立,才会返回true,浏览器才会渲染。只要其中有一个条件不符合,都不会渲染。

or

@supports (property1: value1) or (-webkit-property1: value1) {
  element {
    -webkit-property1: value1;
    property1: value1;
  }
}

多个条件中只要有一个条件成立,就会返回true。所以只要满足其中一个条件,浏览器就会渲染。只有所有都件都不满足,才会返回false,浏览器不渲染。

not

前面也简单说过了,当在@supports中使用not时,表示浏览器不支持条件块中的条件,对应的样式将会渲染。

@supports not(property: value) {
    element {
        ...
    }
}

在实际使用当中,还可以把orand混合一起使用:

@supports ((property1: value1) or 
          (-webkit-property1: value1)) and 
          (property2: value2) {
  element {
    -webkit-property1: value1;
    property1: value1;
    property2: value2;
  }
}

@supports使用示例

如果坚持阅读到这里的话,对于@supports如何使用并不是一件难事了。接下来,还是来看两个简单的示例。

先来看一个有关于CSS的Shapes方面的案例。CSS中的Shapes可以帮且我们排版不再局限于矩形块,可以使用各种图形。但支持该属性的浏览器很少。拿他来做@supports将是一个很好的示例:

.shape{
    width: 20em;
    height: 20em;
    float: left;
    margin: 0.25em 2em 1em 0;
}
@supports (shape-outside: circle()) {
    .shape {
        shape-outside: circle(50%);
        border-radius: 25em;
    }
}

如果你的浏览器支持CSS Shapes的属性,那么你看到的效果是下图左侧的样子,否则看到的是右侧的样子:

supports

再来看一个首字下沉的案例,我们以前做首字下沉一般都是这样来做:

p::first-letter {
   float: left;
   font-size: 5em;
   line-height: 1;
   font-weight: bold;
   margin-right: .2em; 
   color: #00FFFF;
   font-family: serif;
}

但在CSS中有一个initial-letter属性,可以更轻松的实现首字下沉的效果。只是目前浏览器支持度非常非常的少。那么使用@supports,我们可以这样来处理:

@supports (initial-letter: 5) or (-webkit-initial-letter: 5) {
    p::first-letter {
      	-webkit-initial-letter: 5;
      	initial-letter: 5;
      	color: #00FFFF;
      	font-weight: bold;
      	margin-right: 0.5em;
      	font-family: serif;
   	}
}

一旦有一天,浏览器支持了initial-letter属性,你的浏览器将会渲染@supports中的代码块,实现首字下沉效果。

supports

CSS.supports()接口

到今天为止有一个supports()函数可以帮助我们更好的利用CSS特性查询功能。在使用当中,可以通过两种方式来调用CSS.supports()

// 第一种方式
CSS.supports('mix-blend-mode', 'overlay'); // true

// 第二种方式
CSS.supports('(mix-blend-mode: overlay)'); // true

如果浏览器支持supports()中的条件则返回true,否则返回false

CSS.supports('(initial-letter: 5)'); //false

这样一来,就可以很容易根据.supports()来做一个判断,做一些事情。比如说,如果浏览器支持mix-blend-mode: luminosity 我就给目标元素添加luminosity-blend类名,否则就给目标元素添加noluminosity类名。

var init = function() {
  var test = CSS.supports('mix-blend-mode', 'luminosity'),
  targetElement = document.querySelector('img');

  if (test) {
    targetElement.classList.add('luminosity-blend');
  } else {
    targetElement.classList.add('noluminosity');
  }
};
window.addEventListener('DOMContentLoaded', init, false);

比如下面这个DEMO:

总结

在这篇文章中,简单的了解了如何使用CSS的条件属性@supports以及CSS.supports()方法怎么对CSS特性做查询,用来判断浏览器是否支持这些最新的属性。如果支持将返回的是一个true,将会渲染对应的样式;如果不支持,则将返回false,将不会渲染对应的样式。

虽然CSS的@supports得到了很好的支持,但如果在项目中使用@supports的话,建议还是在项目中添加相关的polyfill,比如@Han Lin Yap的css-supports.js或者@termi的CSS.supports

参考文档