文章目录
- 1.5 渐进式增强
- 1.5.1 利用层叠规则实现渐进式增强
- 1.5.2 渐进式增强的选择器
- 1.5.3 利用 `@supports()` 实现特性查询
- 启用浏览器实验特性
1.5 渐进式增强
要用好 CSS 这样一门不断发展演进中的语言,其中一个重要的因素就是要与时俱进,及时了解哪些功能是新鲜出炉的,尤其是那些仅有部分常见浏览器支持的新功能,提前了解是很有必要的。
CSS 同时支持向前与向后兼容的精心设计,让样式代码能够同时在旧新两大类浏览器中流畅运行。只需稍加考虑,这些前沿特性就能在您的 CSS 中得以完美呈现,即便它们尚未对所有用户开放。
为此,可以给旧版浏览器设计一套可接受(但功能较少)的 CSS 样式;而把那些只能在最新版浏览器中呈现的新特性放到新的 CSS 图层(layer)上。这么一来您的样式代码就是面向未来的,随着升级浏览器的用户越来越多,这些新功能新特性也将逐步登台亮相。这种实现方案就叫做 渐进式增强(progressive enhancement)。
想知道一项特定功能的浏览器版本支持情况,请查看 https://caniuse.com 或 MDN 相关文档 https://developer.mozilla.org/en-US/docs/Web。
由于在互联网早期浏览器更新迭代的速度较慢,一些开发人员就总认为那些全新的 CSS 特性几年内都难登大雅之堂。但时至今日,所有主流浏览器都是基业常青的,其新版本的更新发布不仅频繁,而且往往是自动进行的。一些新功能仅仅只需数月就能将浏览器的支持率从 0% 拉升至 80%。之后便会因为用户延迟更新或者囿于公司政策而使更新速度放缓。但无论如何,只要没有明确需求要支持旧版浏览器,新特性通常都会在得到主流浏览器支持后的一两年内稳定下来。
利用适当的渐进式增强配置,您甚至可以即刻小试牛刀,无需恭候多时——尽管也得看该功能的具体适配情况,以及您希望尝试新特性的迫切程度。
1.5.1 利用层叠规则实现渐进式增强
启用渐进式增强最简单的办法是将其构建到层叠规则之中。当浏览器遇到无法解析的样式声明,会直接忽略。考察如下样式代码:
aside {
background-color: #333333; /* 设置一个既安全又普遍支持的十六进制颜色值 */
background-color: #333333aa; /* 使用更新的十六进制编码格式覆盖上一个值 */
}
因为第二个样式声明出现在第一个之后,利用前面介绍的层叠规则,就能断定这些元素的背景色层叠值最终花落谁家。
第二个声明使用了一个相对较新的八位的十六进制颜色编码格式(第 7 位和第 8 位数指定了一个 alpha
通道值,表示部分透明)。该语法在大多数浏览器中均有效,仅有部分旧版浏览器不支持,例如 Internet Explorer 浏览器。因此,如果用户恰巧用的是 IE 浏览器,该样式就会被忽略,层叠值为第一个样式声明的值。尽管该用户无法获得带透明效果的完整体验,但至少还能看到一个完全可用的版本。当前页面不会因此而“崩溃”或抛出错误;浏览器也会继续解析其余 CSS 并丢弃未能识别的样式声明。
从调试的角度来看,这样的处理似乎有些奇特,因为 CSS 从不抛出任何错误。但这恰恰是 CSS 正常运行的一个重要组成部分,也是为了实现渐进式增强的最终目标而精心设计的。
1.5.2 渐进式增强的选择器
渐进式增强的实施并不仅限于新的属性或新的样式值语法层面,还可以体现在新的选择器上。浏览器如果支持该语法就能正常渲染,否则将忽略整个规则集。
还有一个重要细节需要特别注意:当规则集有多个选择器时,只要任何一个选择器不被支持或无效,浏览器渲染时将忽略整个规则集。例如以下样式代码:
input.invalid,
input:user-invalid {
border: 1px solid red;
}
本书撰稿时,伪类 :user-invalid
还是 CSS 的一个新增特性(更多详细信息,请参阅 附录 A)。落后几个版本的浏览器或许理解 input.invalid
的含义,但由于无法理解 :user-invalid
,即使第一个选择器匹配成功,这些样式也同样不会生效。
要启用这样的新选择器,最好的办法是将它们分开书写:
input.invalid {
border: 1px solid red;
}
input:user-invalid {
border: 1px solid red;
}
这将不可避免地引入冗余样式,但也是当下最好的解决方案了。在使用新的伪类、伪元素或者属性选择器时,请务必牢记这一点(请参阅 附录 A)。
遇到上面列举的几个简单情况,尚且只需要重复几行样式代码;但偶尔也会遇到需要重复大段 CSS 的情况。这种情况下,一些开发人员为了尽量避免样式冗余很可能会选择一直等下去,直到浏览器对该选择器的支持情况令人满意后,才会谨慎启用新的功能特性。
1.5.3 利用 @supports()
实现特性查询
前面提到的分而治之的方法,足以应对因启用新特性而对现有样式的影响较小的情况;但偶尔也会遇到给支持新特性的浏览器定制多套不同样式声明的复杂情况。此时就可以利用 CSS 的 特性查询(feature query) 技术,根据浏览器是否支持某个功能特性来定制化开发更大规模的样式效果。
特性查询的写法类似:
@supports (display: grid) { … }
注意,@supports
规则后面有一个带括号的样式声明。如果浏览器能识别该声明(本例即为网格布局),则后面大括号内的所有规则集都会生效,否则予以忽略。
也就是说,您可以提供一套旧的样式布局(如浮动布局)留待备用。这些样式未必是最理想的方案,甚至不得不做出一些让步,但足以满足实际需求。然后再利用特性查询,让完整版的网格布局样式在页面生效。
网格布局方案目前已在所有现代浏览器中得到广泛支持,但以前却并非如此。用它来演示 @supports
的用法再好不过。如图 1.15 所示,在示例页面添加一组超链接,并将其布局到一个小型网格中:
图 1.15 定义在 @supports
代码块内的一组链接网格
首先,将如下 HTML 代码添加到页面标题和页脚之间的 <main>
元素中:
代码清单 1.24 添加到页面的一组超链接
<p>Try some of our newest coffees:</p>
<div class="coffees">
<a href="/coffees/costa-rica">Costa Rica</a>
<a href="/coffees/ethiopia">Ethiopia</a>
<a href="/coffees/guatamala">Guatemala</a>
<a href="/coffees/kenya">Kenya</a>
<a href="/coffees/mexico">Mexico</a>
</div>
接着添加样式,将其设置为网格布局。首先,给旧版浏览器提供一套回退样式;然后利用特性查询,再提供一套完整功能的网格布局版本。代码如下:
代码清单 1.25 利用功能查询来实现渐进式增强
.coffees {
margin: 20px 0;
}
.coffees a {
/* 为旧版浏览器提供一套回退样式 */
display: inline-block;
min-width: 300px;
padding: 10px 15px;
margin-right: 10px;
margin-bottom: 10px;
color: black;
background-color: transparent;
border: 1px solid gray;
border-radius: 5px;
}
@supports (display: grid) { /* 仅对能识别网格布局的浏览器生效如下样式 */
.coffees {
/* 为现代浏览器定义网格布局 */
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
}
.coffees a {
/* 覆盖干扰当前网格布局的回退样式 */
margin: unset;
min-width: unset;
}
}
上述代码中,备用方案和其他基本样式(如颜色)位于特性查询代码块外,因此将对所有浏览器生效。在不支持网格布局的浏览器中打开示例页面,会看到类似网格布局的备用样式效果;而所有基于网格布局的相关样式都在特性查询代码块内,因此仅在浏览器支持网格布局时才会生效。
本书第 5 章还会进一步深入考察网格布局,如果对上述代码不熟悉也无须担心。
试想一下要是没有 @supports
代码块,最终样式会有何不同;甚至可以临时注释掉里面的样式,在现代浏览器中查看样式回退的效果,再酌情调整。
@supports
规则可用于查询各种 CSS 特性的支持情况:使用 @supports (mix-blend-mode: overlay)
可以查询混合模式(blend mode)的支持情况(详见本书第 11 章);使用 @supports (color: color-mix(in oklab, red, white))
还能查询 color-mix
特性的支持情况(详见本书第 13 章)。
CSS 特性查询还支持以下几种写法:
@supports not(<declaration>)
——仅当目标声明不受支持时,生效特性查询块中的特定样式规则;@supports (<declaration>) or (<declaration>)
——支持任一目标声明,则生效对应的样式规则;@supports (<declaration>) and (<declaration>)
——同时支持两个目标声明,则生效相应的样式规则;@supports selector(<selector>)
——仅当浏览器能识别目标选择器时,生效相应的样式规则(例如@supports selector(:user-invalid)
)
有了渐进式增强的解决方案,您可以实现跨浏览器为所有用户提供定制化的用户体验,甚至包括今后的浏览器。一个新的 CSS 语法特性,放到能识别的浏览器内就能渲染,无法识别的也自然不会渲染。Web 设计师兼教育家 Jen Simmons 半开玩笑地称它为“量子 CSS”(Quantum CSS):对于一个 CSS 特性,“可以同时拥有启用和不启用、生效和不生效两种状态”(“use it and not use it at the same time. It works and it doesn’t work at the same time”)。
CSS 的这种语言特性又被称为 CSS 的 弹性机制(resilience)。CSS 这门语言(以及类似的 HTML 语言)是高容错设计理念的产物。随着将来 CSS 新功能的不断涌现,您可以充分利用它来扩充自己的工具箱。
启用浏览器实验特性
W3C 联盟与浏览器厂商一道共同制定并开发了 CSS 规范。这也意味着在 CSS 规范最终确定之前,一些浏览器可能就已经开始支持某项特性功能的研发了。为了防止正处在生产环境中的网站贸然引入尚待稳定的 CSS 样式效果,这些实验性功能仅对有意在浏览器设置中启用它们的开发人员开放。这样也有利于在规范最终确定前进行早期实验和效果反馈。如果您也想接触这些实验性功能,知道如何开启它们也是至关重要的。
在 Chrome 和 Opera 中,可以通过启用一个标志开关(flag)来完成该操作。在 Chrome 的地址栏内输入 chrome://flags
并按 Enter
键跳转;Opera 浏览器则跳转至 opera://flags
。然后下翻或搜索找到“实验性网络平台功能”(Experimental Web Platform Features),并单击启用该选项。
如果习惯用 Firefox 浏览器,则需要下载并安装 Firefox 开发者版本(https://www.mozilla.org/en-US/firefox/developer/)或 Firefox Nightly 版本(https://nightly.mozilla.org/)。如果习惯用 Safari 浏览器,则需要安装 Safari 技术预览版(Safari Technology Preview)或 Webkit Nightly Builds 版本。