使用CSS变量

自定义属性(有时候也被称作CSS变量或者级联变量)是由CSS作者定义,它包含的值可以在整个文档中重复使用。由自定义属性标记设定值(比如: --main-color: black;),由var() 函数来获取值(比如: color: var(--main-color);
复杂的网站都会有大量的CSS代码,通常也会有许多重复的值。举个例子,同样一个颜色值可能在成千上百个地方被使用到,如果这个值发生了变化,需要全局搜索并且一个一个替换(很麻烦哎~)。自定义属性在某个地方存储一个值,然后在其他许多地方引用它。另一个好处是语义化的标识。比如,--main-text-color 会比 #00ff00 更易理解,尤其是这个颜色值在其他上下文中也被使用到。
自定义属性受级联的约束,并从其父级继承其值。

基本用法

声明一个自定义属性:

element {
  --main-bg-color: brown;
}

使用一个局部变量:

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

使用自定义属性的第一步

我们从这个简单的css代码开始,它将相同的颜色应用在了不同class的元素上:

.one {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 50px;
  height: 50px;
  display: inline-block;
}

.two {
  color: white;
  background-color: black;
  margin: 10px;
  width: 150px;
  height: 70px;
  display: inline-block;
}
.three {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 75px;
}
.four {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 100px;
}

.five {
  background-color: brown;
}

我们应用在这个HTML上:

<div>
  <div class="one">1:</div>
  <div class="two">2: Text <span class="five">5 - more text</span></div>
  <input class="three">
  <textarea class="four">4: Lorem Ipsum</textarea>
</div>

其呈现是:

注意到在css代码中的重复:背景色 brown 在多个地方被设置。对于一些CSS声明,是可以在级联关系更高的位置设置,通过CSS继承自然地解决这个重复的问题。但在一般项目中,是不可能通过这样的方式去解决。通过在 :root 伪类上设置自定义属性,然后在整个文档需要的地方使用,可以减少这样的重复性:

:root {
  --main-bg-color: brown;
}

.one {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 50px;
  height: 50px;
  display: inline-block;
}

.two {
  color: white;
  background-color: black;
  margin: 10px;
  width: 150px;
  height: 70px;
  display: inline-block;
}
.three {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 75px;
}
.four {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 100px;
}

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

这里呈现的结果和前面的例子是一致的,但允许对所需属性值进行一个规范的声明。

解决的问题

在构建大型站点时,作者通常会面对可维护性的挑战。在这些网页中, 所使用的 CSS 的数量是非常庞大的,并且在许多场合大量的信息会重复使用。例如,在网页中维护一个配色方案,意味着一些颜色在CSS文件中多次出现,并被重复使用。当你修改配色方案时,不论是调整某个颜色或完全修改整个配色,都会成为一个复杂的问题,不容出错,而单纯查找替换是远远不够的。

如果使用了 CSS 框架,这种情况会变得尤其糟糕,此时如果要修改颜色,则需要对框架本身进行修改。在这些场合使用 LESS 或 Sass 类似的预处理器是非常有帮助的,但是这种通过添加额外步骤的方式,可能会增加系统的复杂性。CSS变量为我们带来一些预处理器的便利,并且不需要额外的编译。

这些变量的第二个优势就是名称本身就包含了语义的信息。CSS 文件变得易读和理解。main-text-color比文档中的#00ff00更容易理解,特别是同样的颜色出现在不同的文件中的时候。

自定义属性的继承性

自定义属性会继承。这意味着如果在一个给定的元素上,没有为这个自定义属性设置值,在其父元素上的值会被使用。看这一段HTML:

<div class="one">
  <div class="two">
    <div class="three"></div>
    <div class="four"></div>
  </div>
</div>

装饰的CSS是:

.two {
  --test: 10px;
}

.three {
  --test: 2em;
}

在这个情况下, var(--test) 的结果分别是:

  • 对于 class="two" 元素:10px

CSS变量能帮助我们干什么

在一些命令式编程语言中,像Java、C++亦或是JavaScript,通过变量我们能够跟踪某些状态。变量是一种符号,关联着一个特定的值,变量的值能随着时间的推移而改变。

在像CSS这种声明式语言中,随着时间而改变的值并不存在,也就没有所谓变量的概念了。

CSS 引入了一种层级变量的概念,从而能够从容应对可维护性的挑战。这就会使得在整个 CSS tree 中都可以象征性的引用一个变量。

什么是CSS变量

CSS 变量当前有两种形式:

  • 变量,就是拥有合法标识符和合法的值。可以被使用在任意的地方。可以使用var()函数使用变量。例如:var(--example-variable)会返回--example-variable所对应的值
  • 自定义属性。这些属性使用--*where*的特殊格式作为名字。例如--example-variable: 20px;即使一个css声明语句。意思是将20px赋值给--example-varibale变量。
注意:在之前的标准中,自定义属性以var-作为前缀,后来才改成--前缀。Firefox 31和以后的版本遵循新标准。(bug 985838)

自定义属性和常规属性一样,作用在当前的层级,若没有定义,则从其父元素继承其值。

开始使用CSS变量

让我们从这个简单的例子开始,拥有不同类名的元素有相同的颜色:

.one {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 50px;
  height: 50px;
  display: inline-block;
}

.two {
  color: white;
  background-color: black;
  margin: 10px;
  width: 150px;
  height: 70px;
  display: inline-block;
}
.three {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 75px;
}
.four {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 100px;
}

.five {
  background-color: brown;
}

把它应用到下面这段HTML:

<div>
    <div class="one"></div>
    <div class="two">Text <span class="five">- more text</span></div>
    <input class="three">
    <textarea class="four">Lorem Ipsum</textarea>
</div>

会得到下面的结果:

注意CSS中重复的地方,brown的背景色作用在不同的元素上面。我们可以将背景色定义在更高的层级,然后通过CSS继承解决这个问题。在某些情况下,这种方法不一定可行。定义一个变量在:root伪类上,使用变量来减少重复的代码。

:root {
  --main-bg-color: brown;
}

.one {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 50px;
  height: 50px;
  display: inline-block;
}

.two {
  color: white;
  background-color: black;
  margin: 10px;
  width: 150px;
  height: 70px;
  display: inline-block;
}
.three {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 75px;
}
.four {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 100px;
}

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

<div>
    <div class="one"></div>
    <div class="two">Text <span class="five">- more text</span></div>
    <input class="three">
    <textarea class="four">Lorem Ipsum</textarea>
</div>

只需要规范地声明所需的属性,就能得到和上面例子相同的结果

CSS变量的继承

自定义属性同样支持继承。一个元素上没有定义自定义属性,该自定义属性的值会继承其父元素:

<div class="one">
  <div class="two">
    <div class="three">
    </div>
    <div class="four">
    </div>
  <div>
</div>

定义下面的CSS:

.two { --test: 10px; }
.three { --test: 2em; }

在这个例子中,var(--test)的结果是:

  • class="two" 对应的节点: 10px
  • class="three" 对应的节点: element: 2em
  • class="four" 对应的节点: 10px (inherited from its parent)
  • class="one" 对应的节点: 无效值, 即此属性值为未被自定义css变量覆盖的默认值

有效性(validity)和值

在传统的CSS概念里,属性的有效性(validity)对于自定义属性来讲,并不适用。当自定义属性被解析,浏览器不知道哪里为调用到它们,所以几乎所有的值都是有效的。

不幸的是,这些有效值能通过var()函数操作符来调用,即使在当前上文没有意义。属性和自定义的值会导致无效的CSS声明,所以有了计算时有效(valid at computed time)的概念。

浏览器支持

We're converting our compatibility data into a machine-readable JSON format. This compatibility table still uses the old format, because we haven't yet converted the data it contains. Find out how you can help!
Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Basic support None 29 (29) (disabled by default behind layout.css.variables.enabled option using old var-varname syntax)
31 (31) (enabled by default)
? ? ?
Feature Android Firefox Mobile (Gecko) IE Phone Opera Mobile Safari Mobile
Basic support ? 29 (29) ? ? ?

[1] Chrome浏览器默认支持的值为添加-webkit-内核前缀的-webkit-var属性. 在-webkit-var()方法中无需定义前缀. 此外, 此功能隐藏于 chrome://flags, 或称之为Enable experimental Web Platform features 开发者设置中的 Enable experimental WebKit features 选项。

[2] Chrome 34.0 y.因某些性能问题移除了此属性。

[3] 此功能在 layout.css.variables.enabled 之后发布, 默认值为false ,Gecko 29默认支持较老的var-variablename 语法规则. 自 Gecko 31 开始此功能被默认开启并启用--variablename 语法规则

了解更多: