使用CSS的currentColor变量扩展颜色级联

发布于 彦子

如果你有使用Sass或LESS,你可能已经在你的样式表中使用过变量了,也知道它们确实非常有用。如果你没有使用预处理器,那么你就可能会好奇这到底是怎么一回事,为什么变量会如此受欢迎,它们为何会这么有用。在这篇文章中,我们先大概讲一下为什么变量如此有用,然后再认识一下另一个特殊的变量:currentColor

变量的好处在哪?

CSS中的变量很有用,因为它们允许我们写更多DRY(不再自我重复,也就是不需要一直写重复内容的代码)代码。它们对于管理和维护大型项目也有非常好用,因为它们包含了大量重复的值。

变量最常见的用例之一是网站或应用程序中的颜色主题/方案。使用变量,在CSS文件中创建并管理颜色方案会容易得多。比如说,在CSS文件中,对于不同的属性,配色方案通常需要重复使用一些颜色值。如果你想要改变某个方案的主要颜色,你就需要在样式表内所有使用了这个颜色的地方进行更改。使用CSS变量,你可以在一个位置定义一个变量(例如,定义一个名为primary-color的变量),赋给它一个颜色值,然后将这个变量作为一个值使用,你就可以在样式表中的任何地方使用它。然后,当你想要改变这个颜色的时候,你需要做的只是为这个变量分配一个不同的颜色值,这样,在样式表中所有使用了这个变量的地方都会自动地更新它们的颜色。

CSS2.1没有引入变量(不过,这也并不完全正确,正如你在这篇文章中看到的)。在2014年,和预处理器变量类似的本地CSS变量被引入了。这些变量可以说甚至比预处理器变量更好用。所有的CSS属性都可以接受一个CSS变量作为值。

除了新变量,CSS还配有一个关键字的值,几乎也相当于是一个变量:currentColor关键字。

currentColor关键字

这个currentColor关键字就像是一个CSS变量,不同的是它有一个主要的限制:你只可以在能够接受<color>的地方使用它;如果该属性不能接受<color>值,它也就不能接受currentColor作为值。

以下是属性中能够接受currentColor为值的使用示例:

box-shadow: inset 2px 2px 3px currentColor;
background-color: currentColor; /* not a good idea! */
background-image: linear-gradient(currentColor, transparent);

currentColor和其它变量之间的另一个区别是,你没办法用给其它变量赋值的方法给它赋值。currentColor的值是由当前元素使用的color属性的计算值决定的。也就是说,currentColor的值和当前color属性的值是一样的,这也是currentColor这个名字的由来。

所以,如果回到我们前面的例子中,currentColor关键字把盒阴影的颜色设置为和div一样的颜色,无论你给div设置的是什么样的color值。如果你没有设置任何的color,它会继承div的任何一个父元素的颜色。如果所有的父元素都没有color,大多数浏览器会直接把它默认设置为黑色。

换句话说:currentColor关键字就是用于设置元素的属性,然后该元素的子元素,就会继承该元素的color属性设置的颜色值。因此,它其实就是作为一个inherit值,允许那些不能通过属性或子元素继承的颜色进行继承。

这也意味着,对于已经继承了color值的属性,currentColor不会再被使用。

默认继承color值的属性和元素

当一个元素有一个color值,无论它是显示设置还是继承的,该元素的某些能够接受<color>值的前景元素将会默认继承该color值。

比如说,元素的边框是元素前景的一部分。因此,即使你没有指定边框的颜色,该边框都会得到和color属性值一样的颜色。如果元素没有color属性值,大多数浏览器通常会默认使用黑色。

这个示例中的边框颜色是紫色的:

.parent {
    color: purple;
}

.child {
    border: 5px solid; /* we didn’t specify the border color here */
}

元素中将会得到/继承元素color值的包括:

  • 元素的文本内容——正是color属性使用的地方
  • 文本的轮廓
  • 元素的边框
  • 元素的盒阴影
  • imgalt文本。也就是,当无法显示图像时,代替图像出现的文本,会继承这个颜色值。
  • 列表项的小黑点和边框
  • 一些浏览器(比如Chrome)水平线(<hr>)的边框颜色。(没有边框的话,颜色就不会受影响)。

如果你没有在某个元素的这些属性中显式地给它们设置颜色,它们就会默认继承元素的color计算值。

下面的demo展示了上述元素属性的应用,它们继承页面中body元素的color值。改变body中的color属性的值,可以看到这些元素的颜色也一起改变了。

此时,你可能会想:如果这么多的属性/元素都继承了color值,currentColor还可以怎么用呢?

使用currentColor扩展颜色继承

在一些可以取color值的地方,使用它是非常方便的。举一个可以使用currentColor的示例,不能继承渐变的color值的地方。CSS渐变图像,无论是线性渐变还是径向渐变,都不能继承颜色。通过使用currentColor,你就可以做一个线性渐变作为背景图像。举个例子,通过调整来匹配你在其它某个地方指定的颜色作为一个主题的“主要颜色”。

background-image: linear-gradient(to bottom, currentColor, #fff);

这里有一个由Scott Kellum创建的示例,他进一步理解了这个概念,并为color属性添加了一个动画效果。在color属性值改变时,所有受到该color影响的元素都会随之改变他们的颜色。查看一下Scott Kellum (@scottkellum)在CodePen上创建的示例currentColor

这是一个使用currentColor的非常棒的示例,特别是动画效果的部分。

不过,关于currentColor的示例还有更多更多,我们一起来看看其中的一些。

currentColor使用实例

currentColor这个属性的主要意义是颜色级联,它能在各种地方派上用场。

currentColor主题UI组件

在之前的demo中,我们可以看到currentColor的一个非常实用(甚至是非常棒的,我必须说)的用例,是去年由Simon “Simurai”在CSSConfau上做的一个分享。这个分享的主要内容是:在UI组件中如何使用Flexbox、currentColorem单位,来快速地直接在浏览器中编写整个Web Apps的样式。

为了演示currentColor的可用性,Simon创建了一组UI元素,包括一些滑动条等。这些元素应用了相同的配色方案。对于滑动条的颜色和输入类型,他使用了currentColor变量来迫使滑动条上滑块的背景颜色继承了color属性,而下方的滑动框则不继承该颜色。

currentColor

一个使用currentColor来让滑动条的滑块应用color属性的值的例子。(地址

同样的,其它的UI组件也可以通过继承级联中某个你想要的位置的color值来创建。由此,一个UI组件就创建好了。然后,利用级联和currentColor,每次你都可以通过改变主要的color值,然后得到一组新颜色的组件,这样几乎就把这整个过程给切实地自动化了。

如下面这个GIF图像所示。Simon使用了浏览器中的开发工具以及颜色拾取器来改变color属性的值,然后得到了一个实时的组件颜色改变的预览。

currentColor

Changing the value of the color property will update the colors of all UI components that are inheriting this color, with the help of the currentColor variable. (Source)

currentColor这个变量的帮助下,改变color属性的值,所有继承了这个color的UI组件的颜色也会跟着改变。(地址

使用浏览器的devtools功能,你可以根据自己的喜好更改主题颜色,然后根据浏览器的样式,在你的文件夹中来保存你所做的更改。像了解关于它的一切,可以参阅Simon的分享还有他的博客文章

使用currentColor设置SVG样式

SVG是非常棒的东西,但是它们有一些样式比较奇特而且有局限性,这取决于你如何使用它们。这种情况下可以使用SVG的<use>元素来重用部分SVG。

如果你对于<use>元素不熟悉的话,你可以在这里查看它所有的相关资料。<use>的意义是重用部分SVG,让我们在页面上的每个我们想要的位置放置这部分SVG的内容。通过use重用SVG元素,我们实际上是创建了该元素的一个同步副本,这和图形编辑器中的“复制 粘贴”操作是类似的。但是这里的复制是同步的,即它的属性会随着初始内容的变化而变化。

<use>元素在创建SVG sprites方面被大量使用。一个包含了所有图标的SVG元素被作为sprite使用,然后我们可以使用<use>在页面上的任何位置插入sprite中的单个图标。你可以在这篇文章中阅读所有的关于SVG创建sprites的内容。

当一个元素被use时,它内容的副本也会被克隆到一个shadow DOM(影子 DOM:一种依附于文档原有节点的子DOM)。也就是说这些内容不可以被CSS选中并编辑样式,和我们在常规的DOM中选择并编辑SVG元素甚至HTML元素样式的方法是不一样的。这是为什么像这样创建SVG样式的图标会受限制的一个原因。

使用currentColor,我们可以绕过这个限制。通过设置currentColor作为我们想要引入颜色值的属性的一个值,可以把我们在CSS中指定的颜色“leak”到使用了use的SVG元素的内容中。

所以SVG图标的use可以这样写:

<svg class="home-icon">
    <use xlink:href="#home"></use>
</svg>

假设在sprites中定义的#home图标包含了如下的内容:

<symbol id="home">
    <rect id="bottom" fill="currentColor" ... />
    <polygon id="roof" ... />
</symbol>

我们可以把样式应用到图标上,然后把fill的颜色级联到#roof(一个没有fill属性的元素),这样color值就会被#bottom这个矩形的fill属性继承。

.home-icon {
    fill: red;
    color: white;
}

fill的颜色将会从svguse级联,然后到#roofcolor值将会被作为#bottom的填充颜色的值,因为currentColor

Fabrice Weinberg前阵子在他的CodePen博客上写了一篇关于这种技术的文章

当你想要创建多组图标,而且每组图标是不同颜色时,这种技术是非常方便的。你需要做的只是根据情况改变CSS中colorfill的值。这种用法的示例在Fabrice的文章中有:

当然,在SVG中你可以在多个元素上使用currentColor。但是,正如你注意到的,它只允许你改变SVG中的两种颜色。

如果你想更多地控制颜色,并指定更多能够引入到SVG中的颜色值,你需要更多的变量。这就是新的CSS变量规范派上用场的时候了。你可以点击这里阅读更多相关内容。

结束语

在前面的例子中,我们看到了如何在多个地方使用currentColor,然后只在一个地方更改我们想要应用到这多个地方的颜色;而不是创建多个相同的颜色,然后全部更改它们。这有助于我们写更短一些的CSS,也为我们提供了某种形式的自动化,特别是像我们在Simon的分享中看到的UI组件。

使用CSS变量,你可以定义你自己的一组变量,然后在相似的或者多用例的情况下使用它们,因为新变量对于所有的CSS属性都是有效值,而不仅是那些只接受<color>值的属性。处理SVG图标肯定会变得越来越容易,维护大型项目也是这样。同样的,如果你使用了预处理器,你就应该已经知道变量是多么有用了。

你可以想到更多使用currentColor情况吗?如果有,请在下面的评论中分享吧~

##扩展阅读

本文根据@Sara Soueidan的《Extending the Color Cascade with the CSS currentColor Variable》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://blogs.adobe.com/dreamweaver/2015/02/extending-the-color-cascade-with-the-css-currentcolor-variable.htmlMatch Jordan 8 Take Flight 23 Camo Military Green T-shirt