文章目录
- 2.6 自定义属性(即 CSS 变量)
- 2.6.1 动态变更自定义属性
- 2.7 本章小结
当前内容所在位置
- 第一章 层叠、优先级与继承
- 第二章 相对单位
- 2.1 相对单位的威力
- 2.2 em 与 rem
- 2.3 告别像素思维
- 2.4 视口的相对单位
- 2.5 无单位的数值与行高
- 2.6 自定义属性 ✔️
- 2.7 本章小结 ✔️
- 第三章 文档流与盒模型
2.6 自定义属性(即 CSS 变量)
自定义属性(Custom properties) 可以实现更高水准的基于上下文的动态样式设计。自定义属性的功能在很多方面都与变量(variables)相似;CSS 可以声明一个变量并赋值,然后在整个样式表中引用该值。这样不仅能减少样式表中的重复,而且还有其他好处,稍后会举例说明。
注意
如果用了 CSS 预处理器(如 Sass 或 Less)自带的变量,那么您可能会忽略 CSS 变量。千万别这么干。由于 CSS 变量有着本质上的区别,它比任何一款预处理器具备的变量功能都要强大得多。因此我更倾向于称其为“自定义属性”,而不是变量,以强调它们和预处理器变量的不同。
定义一个自定义属性,需要像其它 CSS 属性一样进行声明,如下方代码所示。新建一个示例页和样式表,并添加如下 CSS:
:root {
--main-font: Helvetica, Arial, sans-serif;
}
该代码定义了一个名为 --main-font
的变量,并将变量的值设为一组常见的无衬线字体(sans-serif
)。变量名须以两个连字符(--
)开头,以便与其他 CSS 属性作区分;然后再加上要声明的任何合法名称。
CSS 变量必须在声明块中声明。这里用到了 :root
选择器,表示为整个页面设置了该变量,原因稍后解释。
该变量声明只有在被调用时才会在页面看到效果。将它应用到某个段落,则效果如图 2.14 所示:
图 2.14 使用变量设置无衬线字体的普通段落
调用函数 var()
就能使用该变量。使用该函数引用刚才定义的 --main-font
变量。按如下代码更新样式,将变量用起来:
代码清单 2.18 使用自定义属性
:root {
--main-font: Helvetica, Arial, sans-serif;
}
p { /* 将段落字体设置为 Helvetica, Arial, sans-serif */
font-family: var(--main-font);
}
自定义属性可以将值定义到某处作为“单一数据源”,然后在整个样式表中复用该值。这种方式特别适合反复出现在页面上的值,比如颜色值。代码清单 2.19 添加了一个名为 brand-color
的自定义属性,之后整个样式表都能多次调用该变量;后续即便要改,也只需改动这一个地方即可。
代码清单 2.19 使用自定义颜色属性
:root {
--main-font: Helvetica, Arial, sans-serif;
--brand-color: #369; /* 定义一个蓝色的 brand-color 变量 */
}
p {
font-family: var(--main-font);
color: var(--brand-color);
}
var()
函数还能接受一个非必填的第二参数作备用值。如果第一参数设置的变量未定义,则启用第二个备用值。
代码清单 2.20 提供备用值
:root {
--main-font: Helvetica, Arial, sans-serif;
--brand-color: #369;
}
p {
/* 指定备用值为 sans-serif */
font-family: var(--main-font, sans-serif);
/* 变量 secondary-color 未定义,因此启用备用值 blue */
color: var(--secondary-color, blue);
}
上述样式代码在两个不同的声明中指定了备用值。在第一个声明中,--main-font
被定义为 Helvetica, Arial, sans-serif
,因此使用该值;而第二个声明中,变量 --secondary-color
未定义,因此启用备用值 blue
。
注意
如果
var()
函数算出的结果为无效值(invalid value),该属性将被设置为初始值(initial value)。例如,如果padding: var(--brand-color)
中的变量值为一个颜色值,对于内边距padding
而言就是一个无效值。此时padding
的值将被设置为0
。
2.6.1 动态变更自定义属性
在前面的示例中,自定义属性仅仅是为减少大量冗余代码提供了一种便捷方式;而它真正的意义在于,自定义属性的声明也适用 CSS 层叠与继承规则:只要在多个选择器中定义相同的变量,就能让该变量在页面不同位置拥有不同的取值。
例如,将一个变量定义为黑色,然后在特定容器内将其重新定义为白色。这样依赖,任何基于该变量的样式在容器外都将被动态解析为黑色,而容器内则为白色,如图 2.15 所示。
图 2.15 自定义属性会根据本地变量值生成不同颜色的面板
该示例与之前创建的面板效果类似,只是多了一个深色版本。其 HTML 结构如代码清单 2.21 所示。它有两个面板实例:一个在 body
元素内,另一个在深色的 section
元素内。按如下代码更新示例页。
代码清单 2.21 同一页面不同环境下的两个面板
<body>
<div class="panel"> <!-- 网页中的一个普通面板 -->
<h2>Single-origin</h2>
<div class="body">
We have built partnerships with small farms
around the world to hand-select beans at the
peak of season. We then careful roast in
small batches to maximize their potential.
</div>
</div>
<aside class="dark">
<div class="panel"> <!-- 深色容器内的另一个面板 -->
<h2>Single-origin</h2>
<div class="body">
We have built partnerships with small farms
around the world to hand-select beans at the
peak of season. We then careful roast in
small batches to maximize their potential.
</div>
</div>
</aside>
</body>
接下来,通过变量来设置文字颜色与背景色,从而重新定义面板样式。在样式表中添加如下代码,将背景色设置为白色,文字设置为黑色。具体工作原理待面板变为深色版本后再作解释。
代码清单 2.22 使用变量定义面板颜色
:root { /* 分别将背景色和文字颜色变量定义为白色和黑色 */
--main-bg: #fff;
--main-color: #000;
}
.panel {
font-size: 1rem;
padding: 1em;
border: 1px solid #999;
border-radius: 0.5em;
/* 在面板样式中使用变量 */
background-color: var(--main-bg);
color: var(--main-color);
}
.panel > h2 {
margin-top: 0;
font-size: 0.8em;
font-weight: bold;
text-transform: uppercase;
}
这一次同样使用 :root
选择器定义变量——这一点很重要——它意味着这些变量值是为根元素(即整个页面)中的所有内容设置的。当根元素的后代元素调用它们时,浏览器也会解析到这些值。
两个面板准备就绪,尽管看上去效果是一样的。接下来再次定义变量,但选择器和刚才不一样了。以下代码为深色容器设置了深灰色背景,以及少量的内外边距(padding
和 margin
)。此外还重新定义了两个变量。将这些代码更新到样式表中:
代码清单 2.23 深色容器的样式
.dark {
margin-top: 2em; /* 给深色容器与前面的面板之间加上外边距 */
padding: 1em;
background-color: #999; /* 给深色容器加上深灰色背景 */
/* 在容器内重新定义变量的取值: */
--main-bg: #333;
--main-color: #fff;
}
重新加载页面后,第二个面板变为深色背景、白色文字。这是因为当面板使用这些自定义属性时,浏览器会解析在深色容器上定义的变量值,而非根元素上的值。注意,这里无需重新设计面板样式,也不用借助任何其他的样式类。
本例定义了两次自定义属性:先是根元素(此时 --main-color
为黑色),然后是深色容器(此时 --main-color
为白色)。自定义属性是一种带作用域的变量,其值会被后代元素继承。在深色容器中,--main-color
解析为白色;而在页面其他位置,则解析为黑色。
自定义属性是一种用途极为广泛的工具,其用途不胜枚举。本书后续章节还将继续介绍自定义属性的各种应用。
(第一版中曾介绍的第二小节内容:使用 JavaScript 改变自定义属性,在新版中被舍弃了)
2.7 本章小结
- 相对单位可用于指定与字号或视口大小相适应的尺寸。
em
单位制基于该元素字号来定义长度;若用于指定字号本身,则基于该元素继承的字号来定义长度。rem
单位制基于<html>
根元素上设置的字号来定义长度。- 在响应式设计中缩放根元素字号,则页面上用
em
和rem
定义的元素也会同步缩放。 - 视口相对单位基于视口的宽度或高度来定义长度。
- 用无单位数值定义的行高,在继承到子元素时其可预测性更强。
- 自定义属性的工作原理虽然与变量类似,但可以通过层叠和继承规则实现动态调整。
(本章完)