CSS3 的 var 函数

在编写 javascript 时我们深切的体会到变量给我们带来的好处与便利。对于变量的渴求,使Sass/Less/Stylus这些工具应运而生。

在 CSS 预编译器横行的时代,CSS 也不甘落后,为迎合众多前端工程师的需求,CSS工作组迅速跟进CSS变量的规范制定。

:root

在说变量之前还要先了解一个东西 :root 这个 CSS 伪类匹配文档树的根元素。
对于 HTML 来说,:root 表示 <html> 元素,除了优先级更高之外,与 html 选择器相同。

:root在声明全局 CSS 变量时会很有用:

1
2
3
4
:root {
--main-color: hotpink;
--pane-padding: 5px 42px;
}

现在开始步入正题。


自定义属性 (--*)

--* 其中 --是变量名前缀,*是变量名。使用方式是 var(--*); 执行函数var() 是我们接来下介绍的 CSS 函数。
命名规则并没有 CSS 选择器那么多限制。但是,不能包含 $,[,^,(,% 等字符,普通字符局限在只要是“数字[0-9]”“字母[a-zA-Z]”“下划线_”和“短横线-”这些组合,但是可以是中文日文或者韩文
随后脑补了一下以后不用守着翻译器命名了。

语法: <declaration-value>
这个值将会由一个或者多个语法执行出来,只要这些语法是正确合理的,不包含非法语句。这个值就理应是有效语法执行出来的值。

1
2
3
4
5
6
7
8
9
10
:root{
--somekeyword: left;
--somecolor: #0000ff;
--somecomplexvalue: 3px 6px rgb(20, 32, 54);
}

body {
--红色: red;
background-color: var(--红色);
}

var() 函数

var() 函数可以代替元素中任何属性中的值的任何部分。var() 函数不能作为属性名、选择器或者其他除了属性值之外的值。(这样做通常会产生无效的语法或者一个没有关联到变量的值。)

语法:var( <custom-property-name> [, <declaration-value> ]? ) 白话解释就是 var(自定义属性名[, 回退值]) 方法的第一个参数是要替换的自定义属性的名称。函数的可选第二个参数用作回退值。如果第一个参数引用的自定义属性无效,则该函数将使用第二个值。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
:root {
--main-bg-color: pink;
}

body {
background-color: var(--main-bg-color);
}

/* 回退值 */

/* 在父元素样式中 */
.component {
--text-color: #080; /* header-color 并没有被设定 */
}

/* 在 component 的样式中: */
.component .header {
color: var(--header-color, blue); /* 此处 color 被回退到 blue */
}

.component .text {
color: var(--text-color, black); /* 此处 color 被回退到 blue */
}

下面这些个例子与特性详解来自 张鑫旭大神《小tips:了解CSS/CSS3原生变量var》解说的很直观了。

1
2
3
4
5
6
7
8
9
10
11
12
13
<style type="text/CSS">
:root { --color: purple; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
</style>

<p>我的紫色继承于根元素</p>
<div>我的绿色来自直接设置</div>
<div id='alert'>
ID选择器权重更高,因此阿拉是红色!
<p>我也是红色,占了继承的光</p>
</div>

特性

错误使用

无论是变量的定义和使用只能在声明块 {} 里面,例如,下面这样是无效的

1
2
3
4
--红色: red;
body {
background-color: var(--红色);
}

CSS 属性名不可以走变量

1
2
3
4
body {
--bc: background-color;
var(--bc): #369;
}

CSS 不支持同时多个声明

CSS 变量不合法的缺省特性

1
2
3
4
5
6
body {
--color: 20px;
background-color: #369;
background-color: var(--color, #cd0000);
}
/* <body>的背景色是 transparent */

对于 CSS 变量,只要语法是正确的,就算变量里面的值是个乱七八糟的东西,也是会作为正常的声明解析,如果发现变量值是不合法的,例如上面背景色显然不能是 20px,则使用背景色的缺省值,也就是默认值代替

CSS变量的空格尾随特性

1
2
3
4
5
body {
--size: 20;
font-size: var(--size)px;
}
/* 等同于 font-size:20 px */

如果想使用一个数值来贯穿全场-- 推荐使用 CSS3 calc()计算:

1
2
3
4
body {
--size: 20;
font-size: calc(var(--size) * 1px);
}

CSS变量的相互传递特性

就是说,我们在CSS变量定义的时候可以直接引入其他变量给自己使用,例如:

1
2
3
4
body {
--green: #4CAF50;
--backgroundColor: var(--green);
}

或者更复杂的使用CSS3 calc()计算,例如:

1
2
3
4
body {
--columns: 4;
--margins: calc(24px / var(--columns));
}

对于复杂布局,CSS变量的这种相互传递和直接引用特性可以简化我们的代码和实现成本,尤其和动态布局在一起的时候,无论是CSS的响应式或者是JS驱动的布局变化。

作用域

CSS 变量的作用域自上而下,但自下而上引用不会报错警告,只是找不到变量声明而不解析,输出纯字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<style type="text/css">
:root{
--red: red;
}
.wrap{
--white: white;
background-color: var(--red, #f90);
/* 自下而上引用 */
border: 3px solid var(--blue);/* 未声明,不起作用 */
}
.wrap p{
--blue: blue;
color: var(--white, #ccc);
}
/* 兄弟之间引用 */
.wrap2{
background-color: var(--white); /* 未声明,不起作用 */
color: var(--red);
}
</style>

<div class="wrap">
<p>
我是一行逍遥的文字。
</p>
</div>
<div class="wrap2">
<p>
我是第二行同样逍遥的文字。
</p>
</div>

作用域的出现可以避免变量污染,在我看来,使用起 CSS 变量来很有编程的感觉。


js 设置 var

使用 js 设置 var 的值可以使用 setProperty() 方法。

1
2
var box = document.getElementById('id');
box.style.setProperty('--color', '#cd0000');

js 获取 var

使用 js 获取 var 的值可以使用 getPropertyValue() 方法。

1
2
3
4
5
6
// 获取 --color CSS 变量值
var cssVarColor = getComputedStyle(box).getPropertyValue('--color');

// 输出cssVarColor
// 输出变量值是:#cd0000
console.log(cssVarColor);

兼容

  • chrome 49+
  • firefox 49+
  • safari 9.1+
  • opera 41+
  • iOS safari 9.3+
  • ie 不支持

PS:读大神们的文章,禁不住要问为什么看似简单的一个属性,他们却可以探究的如此之深?但一般程序员如我这般只知概念与简单用法就会就此收手。我想这就是大神和我们这些一般程序员的区别----对于未知的追求和迫不及待的挖掘。所以,花费时间,探求挖掘,我们学习的方向。