近年来,一些动态特性已经开始成为 CSS 语言本身的一部分。 CSS变量 – 官方的术语为 “自定义属性” – 已经已经加入规范并且具有很好的浏览器支持,而 CSS mixins 目前正在开发中 。

在本文中,你将了解如何开始将CSS变量集成到CSS开发工作流程中,让你的样式表更好维护,且减少重复。

让我们一起深入了解吧!

什么是CSS变量?

如果你使用过任何编程语言,那么你已经熟悉了变量的概念。变量用于存储和更新你的程序所需要的值,以便使它运行。

例如,请考虑以下JavaScript代码段:


let number1 = 2;
let number2 = 3;
let total = number1 + number2;
console.log(total); // 5
number1 = 4;
total = number1 + number2;
console.log(total); // 7

nubmer1 和 number2 是两个变量,分别存储着数字 2 和 3 。

total 同样是变量,存储着 number1number2 之和。在这里它的值就是 5。你可以动态地修改变量里的值,并在程序中使用它们。在上面的代码中,我把 number1 的值更新为 4,然后再进行求和。使用相同的变量,这个时候 total里存储的值就不再是 5 ,而是 7 了。

变量的好处在于你可以把值存储在一个地方,然后在你需要的地方修改它。这样你就不用在程序的不同地方为不同的值添加不同的变量:所有变量更新使用同一个存储地址,比如你的变量。

CSS在很大程度上是一种声明式的语言,缺乏动态性。你也许会认为,让 CSS 拥有变量,似乎让上面的说法自相矛盾。如果前端开发仅仅关注语义,那可以这么说。幸运的是,Web的编程语言很像生活中的语言,它们会随着周围环境和实践需求而不断进化与适应。CSS也不例外。

总而言之,变量已经成为 CSS 中令人激动的实现,你很快也会发现,对于这个厉害的新技术,学习和使用起来都非常直观。

使用CSS变量有什么好处?

使用CSS变量的好处,跟在其他编程语言中使用变量的好处没什么大的区别。

以下是规范对此的说法:

[使用CSS变量]可以更容易地阅读大文件,因为看似任意的值,现在具有信息性名称,并且使此类文件更容易编辑,且更不容易出错,因为,你只需要在自定义属性中改变一次值,所有应用了这个变量的地方都会自动跟着一起改变。W3C 规范

换句话说:

通过给变量起一个对你来说在项目中有意义的名字,你能更容易的管理和维护你的代码。例如,当你为项目中的主色调设置一个变量名--primary-color ,那么你后面再修改这个主色调时,只需要改动一处,而不需要在不同位置的多个CSS文件中去手动多次修改这个值。

CSS变量和预处理器中的变量有什么不同?

你可能已经在CSS预处理器中尝试过使用变量而带来的好处了,比如 SassLess

预处理器让你能设置变量,以及在函数、循环、数学计算等等地方中使用它们。这是否意味着CSS变量已经无关紧要了呢?

那可未必,主要是因为,CSS变量与预处理器中的变量其实并不是同样的东西。

不同之处在于CSS变量是运行在浏览器中的动态CSS属性,而预处理器变量会被编译成普通的CSS代码。因此,浏览器并不知道预处理器变量的存在。

这意味着,你可以在样式表,内联样式和SVG的标签中直接更新CSS变量,或者使用JavaScript操作它们。这是预处理器变量做不到的。CSS变量提供了更多可能性!

但这并不是说你需要在二者之间选择其一:没有什么东西限制你,你可以同时使用CSS变量和预处理变量,并享有它们各自带来的巨大好处。

CSS变量:语法

虽然本文为了简洁,我使用了CSS变量(CSS variables)这个术语,但是官方的规范把它们称作为 级联变量的CSS自定义属性。CSS自定义属性形式如下:


--my-cool-background: #73a4f4;

在自定义属性前面添加双横线前缀,然后像普通的CSS属性一样给它赋值。在上面的代码片段中,我给 --my-cool-background 自定义属性赋了一个颜色值。

而 级联变量(cascading variable) 的部分,由通过 var() 来使用你的自定义属性,形式如下:


var(--my-cool-background);

自定义属性的作用范围限定在 CSS 选择器中, var() 部分用作实际 CSS 属性的值:


:root {
--my-cool-background: #73a4f4;
}
/* CSS文件的其他部分 */
#foo {
background-color: var(--my-cool-background);
}

上面的代码片段把 --my-cool-background 自定义属性的作用域定义在 :root 这个伪类中,这让该自定义属性能在全局可用(它匹配<html>元素内的所有内容)。然后,使用 var() 函数把 ID 为 foo 的容器的 background-color 设置为自定义属性的值,这时该容器就有了浅蓝的背景色。

除此之外,还可以把淡蓝色应用到多个HTML元素的其他颜色属性上,如 colorborder-color 等。方法很简单,就是通过 var(--my-cool-background) 获取自定义属性的值,然后给相应的CSS属性设置上去。(当然,我建议在事情变得混乱之前考虑一下CSS变量的命名约定):


p {
color: var(--my-cool-background);
}

你也可以在CSS变量中使用另一个CSS变量,例如:


--top-color: orange;
--bottom-color: yellow;
--my-gradient: linear-gradient(var(--top-color), var(--bottom-color));

上面的代码创建了一个 --my-gradient 变量,是一个渐变样式,它的值是使用 --top-color--bottom-color 变量创建的一个渐变。现在,你可以在任何地方通过仅仅改变变量的值来修改渐变,而不必到处在样式表中创建渐变实例。

最后,你可以在CSS变量中加入一个或多个备用值,例如:


var(--main-color, #333);

上面的代码中,#333是一个备用值。如果未设置备用值,则在自定义属性无效或未设置的情况下,将应用继承的值。

CSS变量是区分大小写的

与普通CSS属性不同,CSS变量是区分大小写的。

例如,var(--foo)var(--FOO) 是获取两个不同的自定义属性(分别是 --foo--FOO)的值。

CSS变量受级联关系影响

和普通CSS属性一样,CSS变量是可继承的。例如,我们定义了一个属性,值为 blue :


:root {
--main-color: blue;
}

当你在 <html> 标签中的任意元素指定 --main-color 变量时,它们都会继承到blue这个值。

如果你在另一个元素里面给自定义属性赋了一个不同的值,这个元素的所有子元素就会继承这个新值,例如:

CSS:


:root {
--main-color: blue;
}
.alert {
--main-color: red;
}
p {
color: var(--main-color);
}

HTML:


&lt;--! HTML --&gt;
&lt;html&gt;
&lt;head&gt;
&lt;!-- head code here --&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div&gt;
&lt;p&gt;blue 的段落&lt;/p&gt;
&lt;div class="alert"&gt;
&lt;p&gt;red 的段落&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

在上面的标签中,第一个段落会继承到全局的 --main-color 值,它是蓝色。

在div标签中拥有 .alert 类的段落会是红色,因为它的值继承自局部作用域里的 --main-color ,这个变量的值是 red

内联样式中的 CSS 变量

CSS变量也可以在元素的内联样式中定义。 假设您有一个可以控制大小的组件,

你可以看到元素的内联样式中同样可以定义CSS变量,而且同样遵循相同的级联规则。

var()函数

现在你知道了 var() 函数的用法。有关此功能的更多信息。 看下面的代码,有一个红色的 div 和一个绿色的div。只有一个CSS变量用于子绿色 div

现在从:root选择器 删除CSS变量 --background: green;,看看会发生什么。

你可能猜测子元素将具有从父元素继承的背景红色。 错了,这里有点特殊情况。 当您在任何CSS属性中使用该变量时,如果没有定义变量,那么它将默认采用默认值。 在这个例子中,背景颜色将是transparent(透明的):

你可能猜测子元素将具有从父元素继承的背景红色。 错了,这里有点特殊情况。 当您在任何CSS属性中使用该变量时,如果没有定义变量,那么它将默认采用默认值。 在这个例子中,背景颜色将是transparent(透明的):

无效的值

如果CSS变量有一个无效的值,比如 --background: blah blah blah; 或拼写错误 --background: yelow; /* yellow 拼写错误 */,那么 CSS 属性将默认采用默认值,如:

background 默认值是 transparent
width 默认值是 auto
position 默认值是 static
opacity 默认值是 1
display 默认值是 inline

下面这个例子中,background的值为transparent,也就是说背景颜色是透明的。

回退值(fallback value)

有时可能会出现无法定义CSS变量的情况。在这种情况下,您可以将回退值设置为 var() 函数中的第二个参数

你也可以嵌套多个var() 函数 background: var(--color1, var(--color2, var(--color3, #00BCD4)));

结合 calc()函数

如果你以前从未使用过它,那么我现在告诉你 calc() 函数是一个很实用的小工具,可以让您执行计算以确定CSS值。 它在所有现代浏览器上都得到了很好的支持,并且可以与 CSS变量结合使用,以构建新值。 下面的例子中 <div>width是动态计算的,

结合媒体查询 @media

你甚至可以在媒体查询中重新设置变量值,并让这些新值在任何地方使用它们级联,特别要说明的是:这是预处理器变量无法实现的。

查看此示例,其中媒体查询更改用于设置非常简单网格的变量,打开 codepen,然后尝试调整浏览器的大小,你可以看到媒体查询中的 CSS 变量依然有效。

现在了解这些规则足够,让我们来编码吧!

如何在SVG中使用CSS变量

CSS变量和SVG配合得很好。你可以使用CSS变量去修改SVG中的样式,以及和呈现相关的属性。

比如,你想通过SVG图标元素的父元素来给它一个不同的颜色。你可以在父元素内设置一个局部的CSS变量,然后把它赋值成你想要的颜色,然后,父元素内的图标就能从父元素继承到合适的颜色。

下面是相关代码:


/* 图标的内联SVG symbol */
&lt;svg&gt;
&lt;symbol id="close-icon" viewbox="0 0 200 200"&gt;
&lt;circle cx="96" cy="96" r="88" fill="none" stroke="var(--icon-color)" stroke-width="15" /&gt;
&lt;text x="100" y="160" fill="var(--icon-color)" text-anchor="middle" style="font-size:250px;"&gt;x&lt;/text&gt;
&lt;/symbol&gt;
&lt;/svg&gt;
/* 图标的第一个实例 */
&lt;svg&gt;
&lt;use xlink:href="#close-icon" /&gt;
&lt;/svg&gt;

上面的代码使用了 <symbol> 标签,它让你创建一 SVG 图形的不可见的版本。然后再使用 <use> 标签生成一个可见的副本。这种方法可以让你根据自己的喜好创建任意多个自定义的图标,也就是通过它的ID( #close-icon )指向那个 <symbol> 。这比一遍又一遍地写重复的代码创建图形更加简便。如果你想提高这方便的技术,Massimo Cassandro在他的 创造你自己的SVG图标 中提供了一个快速教程。

注意 SVG中的圆形元素的 stroke 属性值和文本元素的 fill 属性值:它们都使用了一个CSS变量,--icon-color ,这个变量定义在CSS文档的 :root 选择器上,如下所示: 


:root {
--icon-color: black;
}

这是当前图标看起来的样子:

如果你现在把SVG图标放到不同的容器中,然后在每个父元素的选择器中给这个变量赋不同的颜色值,你就能在不添加任何样式规则的情况下创建不同颜色的图标。这很酷!

为了展示这一点,我们把上面图标的一个实例放在一个有 .success 类的 div 中。

HTML 代码:


&lt;!-- html --&gt;
&lt;div class="success"&gt;
&lt;svg&gt;
&lt;use xlink:href="#close-icon" /&gt;
&lt;/svg&gt;
&lt;/div&gt;

现在,让 --icon-color 变量局部化,即把它放在 .success 中,并设置一个 green 值。我们来看看发生的变化:

CSS 代码:


/* css */
.success {
--icon-color: green;
}

这个图标的颜色就变成了绿色:

如何在@keyframes中使用CSS变量

CSS变量可以在CSS动画中使用,不论是在一般的HTML元素还是内联SVG元素上。只需要记得,你得知道让什么元素动,把它视为目标元素,然后创建对该目标元素的选择器,在选择器的作用范围中定义你的CSS变量,然后,使 var() 获取这些变量,把它们设置到 @keyframes 代码块中。

例如,让SVG中 .bubble 类里面的 <ellipse> 元素动起来,你的CSS可能会看起来像这样:


.bubble {
--direction-y: 30px;
--transparency: 0;
animation: bubbling 3s forwards infinite;
}
@keyframes bubbling {
0% {
transform: translatey(var(--direction-y));
opacity: var(--transparency);
}
40% {
opacity: calc(var(--transparency) + 0.2);
}
70% {
opacity: calc(var(--transparency) + 0.1);
}
100% {
opacity: var(--transparency);
}
}

注意到这是如何借助 CSS的 calc() ,并用 var() 函数进行计算的。它们增强了你代码的灵活性。

这个例子简洁的地方在于,利用CSS属性,你可以简单的修改相应选择器里变量值而调整动画,而不需要挨个去查找 @keyframes 里的属性了。

如何通过JavaScript操作CSS变量

另一个超级酷的事情就是,你可以直接通过JavaScript代码访问CSS变量。通过 getComputedStylesetPropertygetPropertyValue从JavaScript访问CSS变量非常简单。 要获取变量,请使用 getPropertyValue()

假设在你的CSS文件中,有一个叫做 --left-pos的变量,作用在 .sidebar 选择器中,值为 100px:


.sidebar {
--left-pos: 100px;
}

那么,使用类似下面的 JavaScript 代码获取 --left-pos 的值:


// 缓存你即将操纵的元素
const sidebarElement = document.querySelector('.sidebar');
// 缓存sidebarElement的样式于cssStyles中
const cssStyles = getComputedStyle(sidebarElement);
// 获取 --left-pos CSS变量的值
const cssVal = String(cssStyles.getPropertyValue('--left-pos')).trim();
// 将CSS 变量的值打印到控制台: 100px
console.log(cssVal);

使用类似下面的JavaScript代码给CSS变量赋值:


sidebarElement.style.setProperty('--left-pos', '200px');

上面的代码将sidebar元素中 --left-pos 变量的值设置为 200px

请看看CodePen中的如下示例,你可以交互式地点击侧边栏,修改 blend mode 属性和背景色。这些实现只用到了CSS变量和JavaScript。

还有一些简单的方法,这里来看看不使用 getComputedStyle(),获取变量值:

JavaScript 代码:


/* 从 :root 根元素获取变量值 */
document.documentElement.style.getPropertyValue('--background');
/* 从 .block-3 元素获取变量值 */
document.querySelector('.block-3').style.getPropertyValue('--background');

修改变量值:


/* 修改 :root 根元素的变量值 */
document.documentElement.style.setProperty('--background', '#ff0000');
/* 修改 .block-3 元素的变量值 */
document.querySelector('.block-3').style.setProperty('--background', '#ff0000');

其他一些注意点
还有一些有趣的事情,在开发时候需要注意。

空值和空格


/* 无效的 */
--color:;
/* 有效的 */
--color: ; /* 值是空格 */

背景图片 url()


/* 无效的 - CSS 不支持拼接*/
.logo{
--logo-url: 'logo';
background: url('assets/img/' var(--logo-url) '.png');
}
/* 无效的 - CSS bug */
.logo{
--logo-url: 'assets/img/logo.png';
background: url(var(--logo-url));
}
/* 有效的 */
.logo{
--logo-url: url('assets/img/logo.png');
background: var(--logo-url);
}

单位相关


/* 无效的 */
--width: 10;
width: var(--width)px;
/* 有效的 */
--width: 10px;
width: var(--width);
/* 有效的 */
--width: 10;
width: calc(1px * var(--width)); /* 乘以1个单位进行转换 */
width: calc(1em * var(--width));

浏览器对CSS变量的支持情况

除了IE11(它不支持CSS变量),所有主流浏览器都对CSS变量有全面地支持。

对于不支持CSS变量的浏览器,一个变通的方案是使用具有虚拟查询条件(dummy conditional query)的 @supports代码块:


section {
color: gray;
}
@supports(--css: variables) {
section {
--my-color: blue;
color: var(--my-color, 'blue');
}
}

因为IE/Edge支持 @supports ,所以上面的代码会生效。如果在var()函数中添加一个后备值,你的代码将会更加健壮,在支持的更加不好的浏览器中也能优雅降级。

所以,在Chrome和其他支持CSS变量的浏览器中,<section>元素内部的文本是蓝色的:

在IE11中,由于它不支持CSS变量,页面将显示灰色文本:

这种方式的缺点是如果你在项目中使用了大量的CSS变量,但是该项目主要通过不支持CSS变量的浏览器打开,那么代码不仅会变得有点儿复杂,维护也将会是噩梦。

在这种情况下,你可以选择使用支持 cssnext 的PostCSS,然后你就可以编写尖端的CSS代码了,兼容不支持的浏览器交给PostCSS去做就可以了,这有点儿像JavaScript的编译器。

这里推荐一下我的前端学习交流群:784783012,里面都是学习前端的,如果你想制作酷炫的网页,想学习编程。自己整理了一份2018最全面前端学习资料,从最基础的HTML+CSS+JS【炫酷特效,游戏,插件封装,设计模式】到移动端HTML5的项目实战的学习资料都有整理

点击:加入

CSS变量实用指南及注意事项的更多相关文章

  1. CSS变量(自定义属性)实践指南

    本文翻译自:https://www.sitepoint.com/practical-guide-css-variables-custom-properties/ 转载请注明出处:葡萄城官网,葡萄城为开 ...

  2. [转载]Firefox插件(plugins)开发实用指南

    转自: http://huandu.me/2010/02/11/595/ Firefox插件可实现强大功能,但其中麻烦事情不少.写这个实用指南首先是为了方便自己记忆,免得以后再次栽倒一些坑里面,如果能 ...

  3. Chrome 控制台实用指南【转】

    转自伯乐在线. Chrome 控制台实用指南 前言 Chrome浏览器我想是每一个前端er必用工具之一吧,一部分原因是它速度快,体积不大,支持的新特性也比其它浏览器多,还有一部分我想就是因为它的控制台 ...

  4. A Practical Guide to Distributed Scrum - 分布式Scrum的实用指南 - 读书笔记

    最近读了这本IBM出的<A Practical Guide to Distributed Scrum>(分布式Scrum的实用指南),书中的章节结构比较清楚,是针对Scrum项目进行,一个 ...

  5. 乙醇的webdriver实用指南ruby版本

    webdriver实用指南是乙醇2013年分享计划的一部分,作为对已逝去的selenium2时代的追忆. 目录如下 启动浏览器 关闭浏览器 浏览器最大化 设置浏览器大小 访问链接 打印当前页面的tit ...

  6. CSS 动画一站式指南

    CSS 动画一站式指南 目录 CSS 动画一站式指南 1. CSS 动画 1.1 变换 1.1.1 变换属性介绍 1.1.2 变换动画实践 1.2 过渡 1.2.1 过渡属性介绍 1.2.2 过渡动画 ...

  7. 引人瞩目的 CSS 变量(CSS Variable)

    这是一个令人激动的革新. CSS 变量,顾名思义,也就是由网页的作者或用户定义的实体,用来指定文档中的特定变量. 更准确的说法,应该称之为 CSS 自定义属性 ,不过下文为了好理解都称之为 CSS 变 ...

  8. 第一个CSS变量:currentColor

    一.基本介绍 CSS变量正慢慢地从最初的草案到浏览器实现.但规范中有个已经存在多年的变量:currentColor.这个CSS特性具有良好的浏览器支持和一些实际的应用,本篇文章,我们来学习和了解它. ...

  9. CSS变量variable

    前面的话 一直以来,CSS中是没有变量而言的,要使用 CSS 变量,只能借助 SASS 或者 LESS 这类预编译器.新的草案发布之后,直接在 CSS 中定义和使用变量不再是幻想了.本文将详细介绍CS ...

随机推荐

  1. [tyvj-2054][Nescafé29]四叶草魔杖 费用流

    lyd讲的最小生成树的题. 道理我都懂,费用流多好写,又好调.但和一般费用流不一样的就是它走过一次后费用需调成0,但是再等回流,就恢复原状即可. #include <queue> #inc ...

  2. Linux操作随笔

    1.查看php加载的模块 /usr/local/php/bin/php -m |less 2.查询连接数 netstat -ntu | awk '{print $5}' | cut -d: -f1 | ...

  3. HDU 2439 The Mussels

    The Mussels Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID ...

  4. Flex AsDoc 完整版

    Flex 生成AsDoc用的是SDK自带的asdoc.exe工具 生成AsDoc文档的方式有两种:ant或者FlashBuilder 外部配置工具 方法一:外部配置工具 新增一个外部配置工具.过程例如 ...

  5. iOS-为方便项目开发在pch加入一些经常使用宏定义

    1.关于NSLog输出 /** * 当Xcode为Release时不输出,为Debug时输出 * * @param ... * * @return */ #ifndef __OPTIMIZE__ #d ...

  6. Maven + SpringMVC + Mybatis

    使用IDEA配置Maven + SpringMVC + Mybatis [一步一步踩坑详细配置完成] PS:初学,想使用Maven配置一个SpringMVC的开发环境,照着网上的各种图文解说,配置了好 ...

  7. Java-MyBatis:MyBatis 3 动态 SQL

    ylbtech-Java-MyBatis:MyBatis 3 动态 SQL 1.返回顶部 1. 动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架 ...

  8. bfs初学

    BFS: ** 当知道初始和目标状态的,用双向BFS: 无权图最好用BFS 不用重复如队** 实现框架: 抄来的(来源:https://www.luogu.org/blog/stephen2333/s ...

  9. ROS-SLAM仿真-hector

    前言:hector_slam可以很好的在空中机器人,手持构图设备及特种机器人中运行. hector_slam不需要订阅里程计信息/odmo消息,而是直接使用激光估算里程计信息,因此,当机器人速度较快时 ...

  10. 移动端 华为手机 input中placeholder垂直居中失效

    为一个app写了一个嵌套的提现页面,效果如下图 input给定宽高,给了line-heigh,在浏览器查看效果正常,placeholder内容以及光标显示都是垂直居中的, IOS显示正常, Andro ...