工具猫
学无止境

css中有一个非常强大的特性查询功能你可能很喜欢

CSS中有一个你可能还没有听说过的工具。 它功能强大。已经存在有一段时间了。并且它可能会成为您最喜欢的关于CSS的新事物之一。

看,它就是@supports规则。 也称为特性查询

使用@supports,您可以在CSS中编写一个小测试,以查看是否支持特定的“功能”(CSS属性或值),并根据答案使用(或不使用)代码块。 如下面这个:

@supports (display: grid) {
   // code that will only run if CSS Grid is supported by the browser 
 }

如果浏览器支持display: grid,则括号内的所有样式将被应用。 否则将跳过所有的样式。

现在,关于功能查询的应用场景似乎有点混乱。 它不是分析浏览器是否正确 实现CSS属性的某种外部验证。 如果你正在寻找上述功能,请去别的地方。 功能查询要求浏览器自动报告是否支持某个CSS属性/值,并根据答案决定是否应用一个CSS块。 如果浏览器实现的功能不正确或不完整,@supports将无法帮助您。 如果浏览器错误得报告了支持哪些CSS,@supports将不会帮助您。 它并不是使浏览器错误消失的魔棒。

也就是说,我发现@supports是非常有帮助的。 @supports规则允许我一再使用新的CSS,远远超过我没有使用它之前。

多年来,开发人员使用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的基本原则。 浏览器只是跳过他们不明白的代码,而不会抛出错误。

大多数浏览器将显示border-radius: 1em就像右侧显示的结果那样。然而,Internet Explorer 6,7和8不会圆角显示,您将会看到左边的结果。在https://codepen.io/jensimmons/pen/EydmkK?editors=1100查看这个示例。

您不需要为此属性使用功能查询。

那么你希望在什么时候使用@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。

回到我们的例子:目前initial-letter仅在Safari 9中支持,它需要一个前缀。 所以我写了前缀,确保也包含那些不需要前缀的版本,我已经同时为两者写了测试。 是的,您可以在您的功能查询中使用orand和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都不支持功能查询。

您可以在 Feature Queries on Can I Use 上查找支持的功能。

您可能会认为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 – 但谁在乎! 我们仍然得到我们想要的结果。

黑莓浏览器和Android的UC浏览器也是一样的。 他们不支持object-fit,也不支持@supports,所以我们都设置好了。 它工作的很好。

底线-当你在浏览器中使用一个不支持功能查询的功能查询时,只要浏览器不支持你正在测试的功能就行了。

想想你的代码的逻辑。 问问自己,浏览器跳过这段代码会发生什么? 如果这是你想要的,你就全部都设置好了。

情况4:浏览器不支持功能查询,但支持相关功能

真正的问题是这第四种组合 – 当使用功能查询编写的测试没有运行,但浏览器确实支持该功能,并且应该运行该代码。

例如,Safari 7.1(Mac)和8(Mac和iOS)支持object-fit,但两个浏览器都不支持功能查询。 Opera Mini也是如此 – 它支持object-fit,但不支持@supports。

将会发生什么呢? 当那些浏览器执行到这些代码块时,它们并不使用这些代码,不会将object-fit:cover应用到图像并将div的背景颜色变为绿色,而是跳过整个代码块,并将黄色作为背景颜色。

这不是我们想要的。

支持功能查询? 支持功能? 发生什么? 是我们想要的吗?
支持功能查询 支持相关功能 应用CSS
支持功能查询 不支持相关功能 没有应用CSS
不支持功能查询 不支持相关功能 没有应用CSS
不支持功能查询 支持相关功能 没有应用CSS 不,可能不是。

当然这取决于具体的用例。 也许这是我们可以接受的结果。 较旧的浏览器会获得针对旧版浏览器的体验。 网页仍然可以运行。

但是很多时候,我们希望浏览器能够使用它支持的任何功能。 这就是当涉及到功能查询时为什么Safari 8可能是最大的问题,而不是Internet Explorer。 Safari 8支持许多较新的属性,如Flexbox。 您可能不想阻止Safari 8使用这些属性。 这就是为什么我很少使用Flexbox的@supports,或者当我使用时,我在代码中至少写了三段代码,其中一个使用了not。 (这很快就变得复杂了,所以我甚至不想在这里解释。)

如果您使用的功能在旧版浏览器中比使用功能查询能够获得更好的支持,则在编写代码时考虑所有组合。 确保不要将浏览器排除在你想要他们获得的代码之外。

同时,使用@supports使用CSS的新特性非常容易 – 例如CSS Grid和Initial Letter。 没有任何浏览器支持CSS Grid而不支持功能查询。 我们不必担心我们的第四个问题与最新功能的组合,这使得功能查询在我们前进的过程中非常有用。

所有这一切意味着,虽然IE11可能会在未来几年内出现,但我们可以使用功能查询轻松使用CSS中的新特性。

最佳实践

所以现在我们知道为什么我们不能这样写我们的代码:

@supports not (display: grid) {
    // 用于旧版浏览器的代码
    // 不要复制这个例子
}
@supports (display: grid) {
    // 用于新版浏览器的代码
    // 我说过这很糟糕吗?
}

如果我们这样做,我们会阻止旧版浏览器获取他们需要的代码。

相反,应该如下构造你的代码:

// 旧版浏览器的备用代码

@supports (display: grid) {
    // 用于新版浏览器的代码
    // 如果需要的话,包括覆盖上面的代码
}

这正是我们在支持旧版本的IE时使用媒体查询的策略。 这个策略就是“移动优先”这个词的来源。

我期望在2017年浏览器能够支持CSS Grid,我敢打赌,在实现未来的布局时,我们将使用大量的功能查询。 与JavaScript相比,它的麻烦要少得多,而且要快得多。 而@supports将让我们为支持CSS Grid的浏览器做一些有趣且复杂的事情,同时为那些不支持CSS Grid的浏览器提供布局选项。

功能查询自2013年中期以来一直存在。 随着Safari 10的即将发布,我相信我们将@supports添加到我们的工具箱已经成为过去。

关于Jen Simmons

Jen Simmons是Mozilla的设计师倡导者,也是The Web Ahead的主持人。 她正在研究网络平面设计的未来,并在全球各地的会议中教授CSS布局。

转载请保留出处:工具猫 » css中有一个非常强大的特性查询功能你可能很喜欢

分享到:更多 ()