浏览器中的 CSS 支持指南

已发表: 2022-03-10
快速总结↬当您想使用某个功能并发现它不受支持或跨浏览器的行为不同时,这可能会令人沮丧。 在这篇文章中,Rachel Andrew 详细介绍了不同类型的浏览器支持问题,并展示了 CSS 是如何发展以使其更易于处理的。

我们永远不会生活在一个每个浏览我们网站的人都拥有相同浏览器和浏览器版本的世界中,就像我们永远不会生活在一个每个人都拥有相同大小的屏幕和分辨率的世界中一样。 这意味着处理旧浏览器——或者不支持我们想要使用的东西的浏览器——是 Web 开发人员工作的一部分。 也就是说,现在的情况比过去好得多,在本文中,我将看看我们可能遇到的不同类型的浏览器支持问题。 我将向您展示一些处理它们的方法,并查看可能即将推出的可以提供帮助的东西。

为什么我们有这些差异?

即使在大多数浏览器都基于 Chromium 的世界中,这些浏览器也并非都运行与 Google Chrome 相同版本的 Chromium。 这意味着基于 Chromium 的浏览器(例如 Vivaldi)可能比 Google Chrome 落后几个版本。

而且,当然,用户并不总是快速更新他们的浏览器,尽管近年来这种情况有所改善,大多数浏览器都在默默地升级自己。

还有新功能首先进入浏览器的方式。 CSS 的新特性并不是由 CSS 工作组设计的,而是将完整的规范传递给浏览器供应商,并附有实现它的说明。 很多时候,只有当一个实验性的实现发生时,规范的所有更精细的细节才能被制定出来。 因此,功能开发是一个迭代过程,需要浏览器在开发中实现这些规范。 虽然这些天来实现通常发生在浏览器中的标志后面或仅在夜间或预览版本中可用,但一旦浏览器具有完整的功能,即使没有其他浏览器支持,它也可能会为每个人打开它。

所有这一切意味着——尽管我们可能喜欢它——我们将永远不会存在于一个功能可以神奇地同时在每个桌面和手机上可用的世界。 如果您是专业的 Web 开发人员,那么您的工作就是处理这个事实。

跳跃后更多! 继续往下看↓

错误与缺乏支持

我们在浏览器支持方面面临三个问题:

  1. 不支持某个功能
    第一个问题(也是最容易处理的)是浏览器根本不支持该功能。
  2. 处理浏览器“错误”
    第二种是浏览器声称支持该功能,但这样做的方式与其他浏览器支持该功能的方式不同。 这样的问题我们倾向于称为“浏览器错误”,因为最终结果是不一致的行为。
  3. 部分支持 CSS 属性
    这个变得越来越普遍; 浏览器支持某项功能的情况——但仅限于一个上下文。

当您看到浏览器之间的差异时,了解您正在处理的问题会很有帮助,因此让我们依次看看这些问题中的每一个。

1. 不支持某个功能

如果您使用浏览器不理解的 CSS 属性或值,浏览器将忽略它。 无论您使用不受支持的功能,还是编造一个功能并尝试使用它,这都是一样的。 如果浏览器不理解那行 CSS,它会跳过它并继续它理解的下一个内容。

CSS 的这种设计原则意味着您可以愉快地使用新功能,因为没有支持的浏览器不会发生任何不好的事情。 对于某些纯粹用作增强的 CSS,这就是您需要做的所有事情。 使用该功能,确保当该功能不可用时,体验仍然很好,仅此而已。 这种方法是渐进增强背后的基本思想,使用平台的这一特性可以在不理解它们的浏览器中安全地使用新事物。

如果您想检查浏览器是否支持您正在使用的功能,那么您可以查看 Can I Use 网站。 寻找细粒度支持信息的另一个好地方是 MDN 上每个 CSS 属性的页面。 那里的浏览器支持数据往往非常详细。

新 CSS 理解旧 CSS

随着新 CSS 功能的开发,需要注意它们与现有 CSS 的交互方式。 例如,在 Grid 和 Flexbox 规范中,详细说明了display: griddisplay: flex如何处理浮动项变为网格项,或多列容器变为网格等场景。 这意味着某些行为被忽略,帮助您简单地覆盖不支持浏览器的 CSS。 这些覆盖在 MDN 上的渐进增强和网格布局页面中有详细说明。

使用功能查询检测支持

上述方法仅在您需要使用的 CSS 不需要其他属性的情况下才有效。 您可能需要为旧浏览器的 CSS 添加其他属性,然后这些属性也将由支持该功能的浏览器进行解释。

使用网格布局时可以找到一个很好的例子。 虽然成为网格项的浮动项会失去所有浮动行为,但如果您尝试为具有浮动的网格布局创建后备,您可能会为项目添加百分比宽度和可能的边距。

 .grid > .item { width: 23%; margin: 0 1%; } 
四列布局
使用浮动我们可以创建一个四列布局,宽度和边距需要在%中设置。 (大预览)

当浮动项目是网格项目时,这些宽度和边距仍然适用。 宽度变成网格轨道的百分比而不是容器的全宽; 然后将应用任何保证金以及您可能指定的差距。

 .grid > .item { width: 23%; margin: 0 1%; } .grid { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; column-gap: 1%; } 
带有压扁列的四列布局
宽度现在是网格轨道的百分比——而不是容器。 (大预览)

值得庆幸的是,有一个内置在 CSS 中并在现代浏览器中实现的功能,可以帮助我们处理这种情况。 功能查询允许我们直接询问浏览器它们支持什么,然后根据响应采取行动。 就像媒体查询(测试设备或屏幕的某些属性)一样,功能查询测试是否支持 CSS 属性和值。

测试支持

测试支持是最简单的情况,我们使用@supports然后测试 CSS 属性和值。 Feature Query 中的内容只有在浏览器响应 true 时才会运行,即它确实支持该功能。

测试不支持

您可以询问浏览器是否不支持某个功能。 在这种情况下,功能查询中的代码只有在浏览器指示它不支持时才会运行。

 @supports not (display: grid) { .item { /* CSS from browsers which do not support grid layout */ } }

测试多种事物

如果您需要支持多个属性,请使用and

 @supports (display: grid) and (shape-outside: circle()){ .item { /* CSS from browsers which support grid and CSS shapes */ } }

如果您需要一个或另一个属性的支持,请使用or

 @supports (display: grid) or (display: flex){ .item { /* CSS from browsers which support grid or flexbox */ } }

选择要测试的属性和值

您不需要测试您想要使用的每个属性 - 只需表明对您计划使用的功能的支持。 因此,如果你想使用网格布局,你可以测试display: grid 。 将来(一旦浏览器支持子网格),您可能需要更具体并测试子网格功能。 在这种情况下,您将测试grid-template-columns: subgrid以仅从那些实现了 subgrid 支持的浏览器中获得真正的响应。

如果我们现在回到我们的浮动后备示例,我们可以看到特征查询将如何为我们排序。 我们需要做的是查询浏览器,看看它是否支持网格布局。 如果是这样,我们可以将项目的宽度设置回auto并将边距设置为0

 .grid > .item { width: 23%; margin: 0 1%; } @supports(display: grid) { .grid { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; column-gap: 1%; } .grid > .item { width: auto; margin: 0; } } 

请参阅 (Rachel Andrew) 在 CodePen 上的 Pen Feature Queries and Grid。

请参阅 (Rachel Andrew) 在 CodePen 上的 Pen Feature Queries and Grid。

请注意,虽然我在功能查询中包含了所有网格代码,但我不需要。 如果浏览器不理解网格属性,它将忽略它们,因此它们可以安全地位于特征查询之外。 在这个例子中,必须在特征查询中的东西是边距和宽度属性,因为这些是旧浏览器代码所需要的,但也会被支持的浏览器应用。

拥抱瀑布

提供回退的一种非常简单的方法是利用浏览器忽略他们不理解的 CSS 的事实,以及在其他所有内容具有相同特异性的情况下,根据将 CSS 应用于元素的方式考虑源顺序.

您首先为不支持该功能的浏览器编写 CSS。 然后测试您想要使用的属性的支持,如果浏览器确认它支持用您的新代码覆盖回退代码。

这与您在使用媒体查询进行响应式设计时可能使用的过程几乎相同,遵循移动优先的方法。 在这种方法中,您从较小屏幕的布局开始,然后在您向上移动通过断点时为较大的屏幕添加或覆盖内容。

我可以使用 CSS 特征查询吗? 来自 caniuse.com 的主要浏览器支持 CSS 功能查询的数据。

上述工作方式意味着您无需担心不支持功能查询的浏览器。 从Can I Use可以看出,Feature Queries 有非常好的支持。 不支持它们的杰出浏览器是任何版本的 Internet Explorer。

但是,您要使用的新功能很可能在 IE 中也不受支持。 因此,目前您几乎总是从为不支持的浏览器编写 CSS 开始,然后使用 Feature Query 进行测试。 此功能查询应测试支持

  1. 支持功能查询的浏览器将在支持时返回 true,因此将使用查询中的代码,覆盖旧浏览器的代码。
  2. 如果浏览器支持功能查询但不支持正在测试的功能,它将返回 false。 功能查询中的代码将被忽略。
  3. 如果浏览器不支持功能查询,那么功能查询块中的所有内容都将被忽略,这意味着 IE11 等浏览器将使用您的旧浏览器代码,这很可能正是您想要的!

2. 处理浏览器“Bug”

幸运的是,第二个浏览器支持问题变得不那么常见了。 如果您阅读了“我们希望什么”(去年年底出版),您可以了解过去一些更令人费解的浏览器错误。 也就是说,任何软件都有可能出现错误,浏览器也不例外。 而且,如果我们再加上一个事实,由于规范实现的循环性质,有时浏览器实现了一些东西,然后规范发生了变化,所以他们现在需要发布更新。 在该更新发布之前,我们可能处于浏览器执行不同操作的情况。

如果浏览器报告对某些东西的支持很糟糕,功能查询就无法帮助我们。 没有一种模式可以让浏览器说:“是的,但你可能不会喜欢它。” 当出现实际的互操作性错误时,正是在这些情况下,您可能需要更有创意。

如果您认为您看到了一个错误,那么首先要做的是确认这一点。 有时,当我们认为我们看到了错误的行为,并且浏览器在做不同的事情时,问题就在我们身上。 也许我们使用了一些无效的语法,或者正在尝试设置格式错误的 HTML。 在这些情况下,浏览器会尝试做一些事情; 但是,由于您没有使用它们设计的语言,因此每个浏览器可能以不同的方式应对。 快速检查您的 HTML 和 CSS 是否有效是很好的第一步。

那时,我可能会快速搜索一下,看看我的问题是否已经被广泛理解。 有一些已知问题的存储库,例如 Flexbugs 和 Gridbugs。 但是,即使是精心挑选的几个关键字,也可以出现涵盖该主题的 Stack Overflow 帖子或文章,并可能为您提供解决方法。

但是,假设您真的不知道是什么导致了这个错误,这使得寻找解决方案变得非常困难。 因此,下一步是为您的问题创建一个简化的测试用例,即剔除任何不相关的内容,以帮助您准确识别触发错误的原因。 如果你认为你有一个 CSS 错误,你可以删除任何 JavaScript,或者在框架之外重新创建相同的样式吗? 我经常使用 CodePen 将我看到的东西的简化测试用例放在一起; 这还有一个额外的好处,就是以一种我可以在需要询问时轻松与其他人分享的方式给我代码。

大多数情况下,一旦您隔离了问题,就有可能想出另一种方法来实现您想要的结果。 你会发现其他人想出了一个巧妙的解决方法,或者你可以在某个地方发帖寻求建议。

话虽如此,如果您认为您有浏览器错误并且找不到其他人谈论相同的问题,那么您很可能发现了应该报告的新内容。 随着最近出现的所有新 CSS,当人们开始将事物与 CSS 的其他部分结合使用时,有时会出现问题。

查看 Lea Verou 关于报告此类问题的帖子,“帮助社区! 报告浏览器错误!”。 这篇文章还提供了创建简化测试用例的重要技巧。

3. CSS属性的部分支持

由于现代 CSS 规范的设计方式,第三类问题变得更加普遍。 如果我们考虑 Grid Layout 和 Flexbox,这些规范都使用 Box Alignment Level 3 中的属性和值来进行对齐。 因此,诸如align-itemsjustify-contentcolumn-gap等属性被指定用于 Grid 和 Flexbox 以及其他布局方法。

然而,在撰写本文时, gap属性在所有支持网格的浏览器中都适用于 Grid Layout,而column-gap则适用于 Multicol; 但是,只有 Firefox 为 Flexbox 实现了这些属性。

如果我要使用边距为 Flexbox 创建后备,然后测试column-gap并删除边距,我的盒子在支持 Grid 或 multicol 中的column-gap的浏览器中将没有空间,所以我的后备间距将是删除。

 @supports(column-gap: 20px) { .flex { margin: 0; /* almost everything supports column-gap so this will always remove the margins, even if we do not have gap support in flexbox. */ } }

这是功能查询的当前限制。 我们没有办法测试另一个功能是否支持某个功能。 在上述情况下,我想问浏览器的是,“Flexbox 中是否支持 column-gap?” 这样,我可以得到一个否定的回应,所以我可以使用我的后备。

CSS 碎片属性break-beforebreak-afterbreak-inside也有类似的问题。 由于这些在打印页面时具有更好的支持,因此浏览器通常会声称支持。 但是,如果您在 multicol 中测试支持,您会得到看似误报的结果。 我已经在 CSS 工作组就这个问题提出了一个问题,但是,这不是一个简单的问题要解决。 如果您有想法,请在此处添加。

测试选择器支持

目前,功能查询只能测试 CSS 属性和值。 我们可能想要测试的另一件事是对较新选择器的支持,例如选择器规范第 4 级中的选择器。 在 Firefox Nightly 中,有一个解释说明和一个标志背后的一个实现,它是功能查询的新功能,它将实现这一点。

如果您在 Firefox 中访问about:config并启用标志layout.css.supports-selector.enabled那么您可以测试是否支持各种选择器。 语法目前非常简单,例如测试:has选择器:

 @supports selector(:has){ .item { /* CSS for support of :has */ } }

这是一个正在开发的规范,但是,您可以看到在我们发言时如何添加帮助我们管理浏览器支持问题的功能。

延伸阅读

当您想使用一项功能并发现一个主要浏览器不支持它,或者事情似乎以不同的方式表现时,这似乎令人沮丧。 我收集了一些可能有帮助的实用进一步阅读。

  • “使用 CSS Grid: Supporting Browsers without Grid”处理旧浏览器和 CSS Grid 的选项
  • 功能查询的“功能查询”MDN 参考页面
  • “CSS 网格和渐进增强” MDN 网格渐进增强指南
  • “Flexbox 的向后兼容性” MDN 对 Flexbox 支持的指南,包括旧前缀实现的详细信息
  • “模式库优先”如何使用模式库管理回退代码