前端在还原设计稿的时候,一般会定义一些 CSS 变量,因为页面配色规则是固定的,把这些搭配做成变量方便后期快速调整,达到升级 UI 甚至换肤的目的。目前所有主流浏览器都支持 CSS 变量了,所以大家可以大胆的用起来。
CSS变量语法
在 CSS 中用两根连词线 --
表示变量(确实很不习惯,因为 sass 和 less 两个预处理器占用了 $
和 @
前缀,为了兼容只能用 --
了,大家忍一下),定义变量的语法为:
--name: value;
其中:
-
name 是变量名。要注意,变量名 name 是大小写敏感的,即:
--name
和--Name
是不同的变量,可以用数字、字母、下划线、短横线进行组合,与其他语言最大的不同是:变量名可以用数字开头,也可以用中文。 -
value 是变量值。可以是一个字符串,例如
'hello'
;也可以是数字,例如:20
;也可以正常的 CSS 值,例如:20px
、red
等。
引用变量的语法为:
var(--name, defaultValue);
例如:
:root {
--1: #ccc;
--蓝色: #369;
}
body {
background-color: var(--1);
color: var(--蓝色, blue);
}
CSS变量作用域
不熟悉 CSS 变量的朋友可能会问::root
是什么意思?其实你可以把它看成全局作用域,里面声明的变量,所有的选择器都可以用。当然,有全局作用域就有局部作用域,例如:
div { --color: red; }
.box { --color: blue; }
#app { --color: green; }
这就是局部作用域,里面定义的 CSS 变量只能在选择器选中的范围内使用。既然如此,也表明在不同选择器下的相同变量名是有优先级的,规则和 CSS 层叠选择器的规则一样。例如:
:root { --font-size: 16px; }
div { --font-size: 15px; }
.box { --font-size: 14px; }
#app { --font-size: 13px; }
* { font-size: var(--font-size); }
最终的结果如下:
<p>16px字体</p>
<div>15px字体</div>
<div class="box">14px字体</div>
<div id="app">13px字体</div>
CSS变量中的陷阱
CSS 变量虽然香,但是有很多陷阱在里面,请听我细说:
important 的陷阱
那有人可能会问,CSS 变量中能不能用 !important
呢?例如:
div { --font-size: 15px;!important }
试试看,发现 .box
和 #app
的字体确实都变成 15px 了,天真的你是不是认为 !important
生效了呢!其实并不是的,我举两个例子:
p {
--font-size: 15px!important;
--font-size: 14px;
font-size: var(--font-size);
}
此时 p 的字体大小的确是 15px,因为写 !important
的同名变量优先级高,chrome 效果如下:
p {
–font-size: 15px !important;
–font-size: 14px;
font-size: var(–font-size);
}
但是请看下面的情况:
p {
--font-size: 15px!important;
--font-size: 14px;
font-size: var(--font-size);
font-size: 13px;
}
此时的字体变成了 13px,chrome 效果如下:
p {
–font-size: 15px !important;
–font-size: 14px;
font-size: var(–font-size);
font-size: 13px;
}
也就是说 !important
只是改变了 CSS 变量的优先级,但是应用的时候并不会影响样式自身的优先级。
值类型的陷阱
之前也讲过 CSS 变量值可以是一个字符串,也可以是数字,也可以正常的 CSS 值,但是大家要注意以下用法之间的区别:
p {
--font-size: '16px';
font-size: var(--font-size); /* 无效 */
}
p {
--font-size: 16;
font-size: var(--font-size)px; /* 无效 */
}
p {
--font-size: 16px;
font-size: var(--font-size); /* 有效 */
}
也就是说 CSS 变量值是一个整体,跟平时我们书写 CSS 规则一样,而不是一种简单的文本替换。但是有一种方法可以:
p {
--font-size: 16;
font-size: calc(var(--font-size) * 1px); /* 有效 */
}
URL替换的陷阱
有时候想把 background 中的 url 做成变量,你可能会这么做:
:root {
--url: "https://pic.cn/a.jpg";
}
.box {
background: url(var(--url));
}
但这样是不对的,你只能这么做:
:root {
--url: url("https://pic.cn/a.jpg");
}
.box {
background: var(--url);
}
想知道为什么吗?可以戳这里
单向数据流的陷阱
猜猜下面 .box
的边框是 1px 呢还是 10px 呢?
:root {
--font-size: 10px;
--border: var(--font-size) solid red;
}
.box {
--font-size: 1px;
border: var(--border);
}
答案是 10px,因为 CSS 变量是单向的,子作用域可以引用父作用域里面的变量,但是反过来是不可以的。