1 起源
2015年,一个期盼已久的CSS规范作为候选推荐标准问世了,叫作层叠变量的自定义属性(Custom Properties for Cascading Variables) 。这个规范给CSS引进了变量的概念,开启了一种全新的基于上下文的动态样式。你可以声明一个变量,为它赋一个值,然后在样式表的其他地方引用这个值,,除了IE,自定义属性已经得到各大主流浏览器的支持。
2 使用
要定义一个自定义属性,只需要像其他CSS属性那样声明即可,如代码清单2-23所示。创建一个新的网页和样式表,将代码清单2-23添加到样式表中。 代码清单2-23 定义一个自定义属性
:root {
--main-font: Helvetica, Arial, sans-serif;
}
这个代码清单定义了一个名叫–main-font的变量。将其值设置为一些常见的sans-serif字体。变量名前面必须有两个连字符(–),用来跟CSS属性区分,剩下的部分可以随意命名。 变量必须在一个声明块内声明。这里使用了:root选择器,因此该变量可以在整个网页使用,稍后会解释这一点。
变量声明本身什么也没做,我们使用时才能看到效果。将这个变量用到一个段落上,就会产生如图2-13所示的结果。 图2-13 该段落使用了变量里定义的sans-serif字体 调用函数var()就能使用该变量。利用该函数引用前面定义的变量–main-font。将代码清单2-24里的规则集添加到你的样式表中。 代码清单2-24 使用自定义属性
:root {
--main-font: Helvetica, Arial, sans-serif;
p { (以下3行)将段落的字体设置为Helvetica、Arial、sans-serif
font-family: var(--main-font);
}
}
在样式表某处为自定义属性定义一个值,作为“单一数据源”,然后在其他地方复用它。这种方式特别适合反复出现的值,比如颜色值。代码清单2-25添加了一个叫brand-color的自定义属性。在样式表中可以多次使用这个变量,当你想要改变这个颜色值时,只需要在一个地方修改即可。 代码清单2-25 使用自定义属性定义颜色
:root {
--main-font: Helvetica, Arial, sans-serif;
--brand-color: #369; ←---- 定义一个蓝色的brand-color变量
}
p {
font-family: var(--main-font);
color: var(--brand-color);
}
var()函数接受第二个参数,它指定了备用值。如果第一个参数指定的变量未定义,那么就会使用第二个值。 代码清单2-26在两个不同的声明中都指定了备用值。在第一个声明里,因为–main-font被定义为Helvetica, Arial, sans-serif,所以使用了这个变量的值。在第二个声明里,因为–secondary-color是一个未定义的变量,所以使用了备用值blue。 代码清单2-26 提供备用值
:root {
--main-font: Helvetica, Arial, sans-serif;
--brand-color: #369;
}
p {
font-family: var(--main-font, sans-serif); ←---- 指定备用值为sans-serif
color: var(--secondary-color, blue); ←---- secondary-color变量没有定义,因此会使用备用值blue
}
说明 如果var()函数算出来的是一个非法值,对应的属性就会设置为其初始值。比如,如果在padding: var(–brand-color)中的变量算出来是一个颜色,它就是一个非法的内边距值。这种情况下,内边距会设置为0。
3 动态改变自定义属性
在前面的示例中,自定义属性只不过为减少重复代码提供了一种便捷方式,但是它真正的意义在于,自定义属性的声明能够层叠和继承:可以在多个选择器中定义相同的变量,这个变量在网页的不同地方有不同的值。
例如,可以定义一个变量为黑色,然后在某个容器中重新将其定义为白色。那么基于该变量的任何样式,在容器外部会动态解析为黑色,在容器内部会动态解析为白色。接下来用这种特性来实现如图 2-14所示的效果。 图2-14 自定义属性基于当前变量值,产生了两种不同颜色的面板
这个面板跟之前的面板(如图2-7所示)类似。它的HTML标记如代码清单2-27所示。代码里的面板有两个实例:一个面板在body里,还有一个面板在深色的区域中。按照代码清单2-27更新HTML。 代码清单2-27 同一个网页中,不同环境下的两个面板
<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"> (以下2行)深色容器内的另一个面板
<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-28加入你的样式表。这会将背景色设置为白色,将文字设置为黑色。在实现深色面板之前,我先解释一下它的工作原理。 代码清单2-28 使用变量定义面板颜色
:root {
--main-bg: #fff; (以下2行)分别将背景色和文字颜色变量定义为白色和黑色
--main-color: #000;
}
.panel {
font-size: 1rem;
padding: 1em;
border: 1px solid #999;
border-radius: 0.5em;
background-color: var(--main-bg); (以下2行)在面板样式中使用变量
color: var(--main-color);
}
.panel > h2 {
margin-top: 0;
font-size: 0.8em;
font-weight: bold;
text-transform: uppercase;
}
首先还是在:root选择器的规则集中定义变量。这很重要,如此一来这些值就可以提供给根元素(整个网页)下的任何元素。当根元素的后代元素使用这个变量时,就会解析这里的值。
我们有两个面板,它们看起来一样。接下来在另一个选择器中重新定义这两个变量。代码清单2-29定义了深色容器的样式,为该容器设置了深灰色背景,还有一些内边距和外边距,同时也重新定义了两个变量。将代码清单2-29添加到样式表中。 代码清单2-29 深色容器的样式
.dark {
margin-top: 2em; ←---- 给深色容器和前面的面板之间加上外边距
padding: 1em;
background-color: #999; ←---- 给深色容器加上深灰色背景
--main-bg: #333; (以下2行)在容器内重定义--main-bg和--main-color变量
--main-color: #fff;
}
重新加载网页,会看到第二个面板有深色背景和白色文字。这是因为面板使用了这些变量,它们会解析成深色容器内定义的值,而不是根元素内定义的值。注意,这里并没有重新定义面板样式,或者给面板加上额外的类。 在本例中,总共定义了自定义属性两次:第一次在根元素上(–main-color为黑色),第二次在深色容器上(–main-color为白色)。自定义属性就像作用域变量一样,因为它的值会被后代元素继承。在深色容器中,–main-color为白色,在页面其他地方,则是黑色。
4 使用JavaScript改变自定义属性
还可以使用JavaScript在浏览器中实时访问和修改自定义属性。本书并不是介绍JavaScript的,所以只会简单介绍概念。需要你自己在JavaScript项目中实现剩下的功能。
代码清单2-30展示了如何访问一个元素上的属性。在网页中插入一个脚本,该脚本记录了根元素的–main-bg属性值。 代码清单2-30 访问JavaScript的自定义属性
<script type="text/javascript">
var rootElement = document.documentElement;
var styles = getComputedStyle(rootElement); ←-- 获取一个元素的styles对象
var mainColor = styles.getPropertyValue('--main-bg'); ←-- 获取styles对象的--main-bg值
console.log(String(mainColor).trim()); ←---- 确保mainColor是一个字符串,并去掉前后空格;打印结果为“#fff”
</script>
因为你可以实时改变自定义属性的值,所以可以用JavaScript为–main-bg动态设置一个新值。如果将其设置为浅蓝色,效果会如图2-15所示。 图2-15 JavaScript可以通过改变–main-bg变量的值,设置面板的背景色
代码清单2-31给根元素上的–main-bg设置了一个新值。将这个代码清单放到
var rootElement = document.documentElement;
rootElement.style.setProperty('--main-bg', '#cdf'); ←---- 将根元素上的--main-bg设置为浅蓝色
如果运行以上脚本,所有继承了–main-bg属性的元素都会更新,使用新的值。在网页中,第一个面板的背景色会改为浅蓝色。第二个面板保持不变,因为它依然继承了深色容器里的属性。
利用这种技术,就可以用JavaScript实时切换网站主题,或者在网页中突出显示某些元素,或者实时改变任意多个元素。只需要几行JavaScript代码,就可以进行更改,从而影响网页上的大量元素。
5 探索自定义属性
自定义属性是CSS中一个全新的领域,开发人员刚刚开始探索。因为浏览器支持有限,所以还没有出现“典型”的用法。我相信假以时日,会出现各种最佳实践和新的用法。这需要你持续关注。继续使用自定义属性,看看能用它做出什么效果。
值得注意的是,在不支持自定义属性的浏览器上,任何使用var()的声明都会被忽略。请尽量为这些浏览器提供回退方案。
color: black;
color: var(--main-color);
然而这种做法不是万能的,比如当用到自定义属性的动态特性时,就很难有备用方案。关注 Can I Use网站,查看最新的浏览器支持情况。
|