CSS中有一个你可能还没有听说过的工具。 它功能强大。已经存在有一段时间了。并且它可能会成为您最喜欢的关于CSS的新事物之一。
看,它就是@supports规则。 也称为特性查询。
使用@supports,您可以在CSS中编写一个小测试,以查看是否支持特定的“功能”(CSS属性或值),并根据答案使用(或不使用)代码块。 如下面这个:
@supports (display: grid) {
// code that will only run if CSS Grid is supported by the browser
}
如果浏览器支持display: grid,则括号内的所有样式将被应用。 否则将跳过所有的样式。
多年来,开发人员使用Modernizr来做功能查询,但Modernizr需要JavaScript。 虽然脚本可能很小,但是使用Modernizr构建的CSS需要在应用CSS之前下载,执行和完成JavaScript文件。 涉及JavaScript总是比仅使用CSS慢。 存在JavaScript打开失败的可能性 - 如果JavaScript不执行会发生什么? 此外,Modernizr引入了一个额外的复杂性,许多项目根本无法处理。 功能查询更快,更强大,使用起来更简单。
@supports (display: grid) {
main {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
}
现在大多数时候,你不需要在你的CSS中进行这样的测试。 例如,您可以编写此代码,而无需测试是否支持:
aside {
border: 1px solid black;
border-radius: 1em;
}
如果浏览器支持border-radius,那么它将在aside
边框上放置圆角。 如果没有,它将跳过该行代码并继续执行,使边框为正方形。 没有理由运行测试或使用功能查询。 这只是CSS的工作原理。 这是建立坚实,逐步增强的CSS的基本原则。 浏览器只是跳过他们不明白的代码,而不会抛出错误。
您不需要为此属性使用功能查询。
那么你希望在什么时候使用@supports?功能查询是一种将CSS声明捆绑在一起的工具,以便它们在特定条件下作为组运行。当您想混用旧的和新的CSS,但只有支持新的CSS时,使用功能查询。
我们来看一个使用Initial Letter属性的例子。这个新的属性initial-letter告诉浏览器使这个元素更大 - 就像首字下沉一样。这里,段落中第一个单词的第一个字母被设定为四行文本的大小。非常好。哦,但是我还想把这个字母加粗,在它的右边增加一点外边距,嘿,让我们把它变成漂亮的橙色。酷。
p::first-letter {
-webkit-initial-letter: 4;
initial-letter: 4;
color: #FE742F;
font-weight: bold;
margin-right: 0.5em;
}
这是我们在Safari 9中看到的 initial-letter示例。
不好了。 所有其他浏览器看起来都很糟糕。
那是不可接受的。 我们不想更改字母的颜色,或添加边距,或使其变为粗体,除非它也将被Initial Letter属性放大。 我们需要一种方法来测试和查看浏览器是否支持Initial Letter,并且仅在其支持时应用颜色,字重和边距。 输入功能查询。
@supports (initial-letter: 4) or (-webkit-initial-letter: 4) {
p::first-letter {
-webkit-initial-letter: 4;
initial-letter: 4;
color: #FE742F;
font-weight: bold;
margin-right: 0.5em;
}
}
请注意,您需要测试一个包含属性和值的完整字符串。 这一开始让我感到困惑。 为什么我要测试initial-letter: 4? 值4重要吗? 如果我把值换成17呢? 它需要进一步匹配我代码中的值吗?
@supports规则测试一个包含属性和值的字符串,因为有时需要测试属性,有时需要测试值。 对于 initial-letter
的例子来说,你所提供的值并不重要。 但是请考虑@supports (display: grid),您将看到需要同时测试这两者。 每个浏览器都支持display。 (目前)只有实验浏览器支持display: grid。
or
, and和
not语句
。
这是新的结果。 支持initial-letter的浏览器显示了一个巨大的粗体橙色首字下沉。 其他浏览器的表现就像首字下沉不存在 - 就像在等到更多浏览器支持之前我必需等待使用此功能一样。 (顺便说一下,我们目前正在Firefox中实现Initial Letter。)
左边的截图来自Safari 9。所有其他浏览器都显示右边的结果。 您可以在这里查看这段代码codepen.io/jensimmons/pen/ONvdYL
组织你的代码
现在,您可能会试图使用此工具将代码清理成两个分支。 “嗨,浏览器,如果你支持Viewport单位,就执行这段代码,如果你不支持他们,就执行另外一段代码。”这感觉又好又整洁。
@supports (height: 100vh) {
// 我使用viewport height的布局
}
@supports not (height: 100vh) {
// 旧版浏览器的替代布局
}
// 我们希望这样,但这是一段糟糕的代码
并不是所有的浏览器都支持功能查询。 对那些不支持@supports的浏览器将同时跳过这两段代码块。 那可能不是我们希望的。
这是否意味着,直到100%的浏览器支持它们才能使用功能查询? 不。 我们可以使用,而且今天就应该使用功能查询。 不要像上一个例子那样写你的代码。
我们如何做到这一点呢? 就像我们在Media Queries100%支持前那样使用。 而且,实际上在这个过渡时期使用功能查询比使用“媒体查询”更容易。 你只要聪明点就行了。
(当然,在未来的某个时候,一旦全部浏览器100%支持功能查询,我们就可以更加重用 @supports not
,并且以这种方式组织我们的代码,但那天来临之前还需要很多年)。
支持功能查询
那么功能查询支持浏览器的哪些历史版本呢?
@supports自2013年中期以来就能在Firefox,Chrome和Opera上工作。 它也适用于每个版本的Edge。 Safari于2015年秋季在Safari 9中支持它。任何版本的Internet Explorer,Opera Mini,Blackberry Browser或UC Browser都不支持功能查询。
您可能会认为Internet Explorer不支持功能查询是一个大问题。 其实,它通常不是。 我一会儿告诉你为什么。 我认为最大的障碍是Safari 8。我们需要密切注意Safari 上发生的事情。
我们来看另一个例子。 我们有一些我们要应用的布局代码,它需要使用object-fit:cover才能正常工作。 对于不支持object-fit的浏览器,我们需要应用不同的布局CSS。
您可以在 Object Fit on Can I Use 上查找支持的对象。
div {
width: 300px;
background: yellow;
// 一些用于旧布局的复杂代码
}
@supports (object-fit: cover) {
img {
object-fit: cover;
}
div {
width: auto;
background: green;
// 一些用于华丽的新布局的复杂代码
}
}
那么会发生什么呢? 功能查询是否被支持,新的功能 object-fit: cover
是否被支持。 结合以上内容,我们得到四种可能性:
支持功能查询? | 支持功能? | 发生什么? | 是我们想要的吗? |
---|---|---|---|
支持功能查询 | 支持相关功能 | ||
支持功能查询 | 不支持相关功能 | ||
不支持功能查询 | 不支持相关功能 | ||
不支持功能查询 | 支持相关功能 |
情况1:浏览器支持功能查询,并支持相关功能
Firefox,Chrome,Opera和Safari 9都支持object-fit和@supports,所以这个测试将运行得很好,并且该块中的代码将被应用。 我们的图像将使用 object-fit: cover
裁剪,我们的div背景将为绿色。
情况2:浏览器支持功能查询,不支持相关功能
Edge不支持object-fit,但它支持@supports,因此此测试将运行并失败,从而防止代码块被应用。 图像将不会应用object-fit,并且div将具有黄色背景。
情况3:浏览器不支持功能查询,不支持相关功能
这就是我们的经典克星Internet Explorer出现的地方。 IE不支持@supports,它也不支持object-fit。 您可能会认为这意味着我们无法使用功能查询 - 但这不是真的。
想想我们想要的结果。 我们希望IE跳过整个代码块。 而这正是将要发生的。 为什么? 因为当它执行到@supports时,它不能识别该语法,并且跳转到结尾。
“出于错误的原因”它可能会跳过代码 - 它跳过代码,因为它不支持@supports,而不是因为它不支持object-fit - 但谁在乎! 我们仍然得到我们想要的结果。
底线-当你在浏览器中使用一个不支持功能查询的功能查询时,只要浏览器不支持你正在测试的功能就行了。
想想你的代码的逻辑。 问问自己,浏览器跳过这段代码会发生什么? 如果这是你想要的,你就全部都设置好了。
情况4:浏览器不支持功能查询,但支持相关功能
例如,Safari 7.1(Mac)和8(Mac和iOS)支持object-fit,但两个浏览器都不支持功能查询。 Opera Mini也是如此 - 它支持object-fit,但不支持@supports。
将会发生什么呢? 当那些浏览器执行到这些代码块时,它们并不使用这些代码,不会将object-fit:cover应用到图像并将div的背景颜色变为绿色,而是跳过整个代码块,并将黄色作为背景颜色。
支持功能查询? | 支持功能? | 发生什么? | 是我们想要的吗? |
---|---|---|---|
支持功能查询 | 支持相关功能 | 应用CSS | 是 |
支持功能查询 | 不支持相关功能 | 没有应用CSS | 是 |
不支持功能查询 | 不支持相关功能 | 没有应用CSS | 是 |
不支持功能查询 | 支持相关功能 | 没有应用CSS | 不,可能不是。 |
当然这取决于具体的用例。 也许这是我们可以接受的结果。 较旧的浏览器会获得针对旧版浏览器的体验。 网页仍然可以运行。
如果您使用的功能在旧版浏览器中比使用功能查询能够获得更好的支持,则在编写代码时考虑所有组合。 确保不要将浏览器排除在你想要他们获得的代码之外。
所有这一切意味着,虽然IE11可能会在未来几年内出现,但我们可以使用功能查询轻松使用CSS中的新特性。
最佳实践
所以现在我们知道为什么我们不能这样写我们的代码:
@supports not (display: grid) {
// 用于旧版浏览器的代码
// 不要复制这个例子
}
@supports (display: grid) {
// 用于新版浏览器的代码
// 我说过这很糟糕吗?
}
如果我们这样做,我们会阻止旧版浏览器获取他们需要的代码。
相反,应该如下构造你的代码:
// 旧版浏览器的备用代码
@supports (display: grid) {
// 用于新版浏览器的代码
// 如果需要的话,包括覆盖上面的代码
}
这正是我们在支持旧版本的IE时使用媒体查询的策略。 这个策略就是“移动优先”这个词的来源。
功能查询自2013年中期以来一直存在。 随着Safari 10的即将发布,我相信我们将@supports添加到我们的工具箱已经成为过去。
关于Jen Simmons
Jen Simmons是Mozilla的设计师倡导者,也是The Web Ahead的主持人。 她正在研究网络平面设计的未来,并在全球各地的会议中教授CSS布局。