CSS 预处理器
概述/简介
在 CSS Houdini 提案之前,CSS 本身不属于可编程语言。当前端项目逐渐庞大之后,CSS 的维护也越来越困难,这时我们就需要 CSS 预处理器通过 工程化 的手段让 CSS 更易维护,提升开发效率。CSS 预处理器本质上是通过 变量 、嵌套语法 、逻辑 、函数 等为 CSS 增加一些可编程的特性。
目前主流的 CSS 预处理器主要有
- Sass
- Less
- Stylus
- PostCSS
调研/统计
据统计过使用 CSS 预处理器首要原因:
- 嵌套语法: 35%
- 变量: 35%
- 函数: 25%
- 其他: 5%
pie title
"嵌套语法" : 35
"变量" : 35
"函数" : 25
"其他" : 5
如果不使用 CSS 预处理器,如何精简 CSS 样式定义?
:is()
:where()
css
/* Normal 样式 */
#card img
#footer img {
/* 优先级权重 = (1,0,1) */
}
/* 使用 :is() 样式 */
:is(#card, #footer) img {
/* 优先级权重 = (1,0,1) */
}
/* 使用 :where() 样式 */
:where(#card, #footer) img {
/* 优先级权重 = (0,0,1) */
}
注意 :is()
和 :where()
的 CSS 优先级权重!
CSS 原生嵌套语法
就如上个小节所述,嵌套语法是使用 Sass/Less 等 CSS 预处理器的核心原因之一。但在小型项目(HTML + CSS + JS)开发中,使用 CSS 预处理器却有些不便且过于厚重,虽然可以通过 :is()
或 :where()
进行简化,但始终无法做到嵌套语法开发时体验和效率。不过现在有了 CSS 原生嵌套语法的支持,一切都迎刃而解。
兼容性
目前主流浏览器都已支持 CSS Nesting
这个特性。查看最新
注意: 该规范的早期版本不允许在没有 &
、@
、:
、.
、>
、~
、+
、#
、[
、*
等选择器的情况下嵌套类型选择器。新版已更新,不再需要嵌套选择器。但是支持度如下:
- 目前 Firefox 支持新版本的规范
- 目前 Chrome 和 Safari 支持旧版本的规范,必须使用嵌套选择器进行类型选择器嵌套,具体后面会进行讲解
基本概念
CSS 嵌套语法
定义了嵌套选择器的语法,提供了将一个样式规则嵌套在另一个样式规则中的功能,子规则的选择器相对于父规则的选择器。
css
/* 使用嵌套语法,但不使用嵌套选择器,根据兼容性情况,目前只有 Firefox 支持 */
parent {
/* parent styles */
child {
/* child of parent styles */
}
}
/* 使用嵌套语法,且使用嵌套选择器,主流浏览器都支持 */
parent {
/* parent styles */
& child {
/* child of parent styles */
}
}
与预处理器区别
- CSS 嵌套语法是由浏览器解析识别
- CSS 预处理器是前端项目在构建期间进行预编译成css
嵌套规则
- CSS选择器
- @media
- @layer
- @scope (暂不提供范例)
- @supports (暂不提供范例)
- @container (暂不提供范例)
范例 - CSS选择器
css
/* 例 1 */
h2 {
& p {
/* h2 p 样式 */
}
}
/* 例 2 */
h2 {
&.p {
/* h2.p 样式 */
}
}
/* 例 3 */
.card {
& h2 {
.featured & {
/* .featured .card h2 */
}
}
}
范例 - media
css
/* 使用嵌套语法 */
.foo {
display: grid;
@media (orientation: landscape) {
grid-auto-flow: column;
@media (min-width > 1024px) {
max-inline-size: 1024px;
}
}
}
/* 等效于下面的语法 */
.foo {
display: grid;
}
@media (orientation: landscape) {
.foo {
grid-auto-flow: column;
}
}
@media (orientation: landscape) and (min-width > 1024px) {
.foo {
max-inline-size: 1024px;
}
}
范例 - layer
css
.foo {
@layer base {
block-size: 100%;
@layer support {
& .bar {
min-block-size: 100%;
}
}
}
}
/* 等效于下面的语法 */
@layer base {
.foo {
block-size: 100%;
}
}
@layer base.support {
.foo .bar {
min-block-size: 100%;
}
}
特异性权重
嵌套选择器的特异性是使用关联选择器列表中的最大特异性计算的。这与使用 :is()
函数时计算特异性的方式相同。
html
<!DOCTYPE html>
<html lang="en">
<head>
<style type="text/css">
#a,b {
& c {
/* 优先级权重 = (1,0,1) */
}
}
.foo c {
/* 优先级权重 = (0,1,1) */
}
/* 等效于下面的语法 */
:is(#a, b) {
& c {
/* 优先级权重 = (1,0,1) */
}
}
.foo c {
/* 优先级权重 = (0,1,1) */
}
</style>
</head>
<body>
<b class="foo">
<c>Blue text</c>
</b>
</body>
</html>
CSS 预处理器的优势还在吗?
- CSS Nesting 原生嵌套语法,主流浏览器均已支持
- CSS 自定义属性/变量,主流浏览器均已支持,详情
- CSS Houdini 公开了 CSS 引擎的各个部分,允许通过JS编程,相比
CSS-In-JS
更加出色,不过目前兼容性有待提高 - CSS 原生函数众多(如
clamp()
、color-mix()
、color-contrast()
等)。虽然离 CSS 预处理器有段距离,但是越来越稳健。
也许不久的将来,我们可以完全不再依赖 CSS 预处理器,做到更好开发体验和效率。