近年来,一些动态特性已经开始成为 CSS 语言自己的一部分。 CSS变量 – 官方的术语为 “自定义属性” – 已经已经加入规范而且具备很好的浏览器支持,而 CSS mixins 目前正在开发中 。css
在本文中,你将了解如何开始将CSS变量集成到CSS开发工做流程中,让你的样式表更好维护,且减小重复。html
让咱们一块儿深刻了解吧!前端
什么是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
一样是变量,存储着 number1
与 number2
之和。在这里它的值就是 5。你能够动态地修改变量里的值,并在程序中使用它们。在上面的代码中,我把 number1
的值更新为 4,而后再进行求和。使用相同的变量,这个时候 total里存储的值就再也不是 5 ,而是 7 了。编程语言
变量的好处在于你能够把值存储在一个地方,而后在你须要的地方修改它。这样你就不用在程序的不一样地方为不一样的值添加不一样的变量:全部变量更新使用同一个存储地址,好比你的变量。ide
CSS在很大程度上是一种声明式的语言,缺少动态性。你也许会认为,让 CSS 拥有变量,彷佛让上面的说法自相矛盾。若是前端开发仅仅关注语义,那能够这么说。幸运的是,Web的编程语言很像生活中的语言,它们会随着周围环境和实践需求而不断进化与适应。CSS也不例外。svg
总而言之,变量已经成为 CSS 中使人激动的实现,你很快也会发现,对于这个厉害的新技术,学习和使用起来都很是直观。
使用CSS变量有什么好处?
使用CSS变量的好处,跟在其余编程语言中使用变量的好处没什么大的区别。
如下是规范对此的说法:
[使用CSS变量]能够更容易地阅读大文件,由于看似任意的值,如今具备信息性名称,而且使此类文件更容易编辑,且更不容易出错,由于,你只须要在自定义属性中改变一次值,全部应用了这个变量的地方都会自动跟着一块儿改变。W3C 规范
换句话说:
经过给变量起一个对你来讲在项目中有意义的名字,你能更容易的管理和维护你的代码。例如,当你为项目中的主色调设置一个变量名--primary-color ,那么你后面再修改这个主色调时,只须要改动一处,而不须要在不一样位置的多个CSS文件中去手动屡次修改这个值。
CSS变量和预处理器中的变量有什么不一样?
你可能已经在CSS预处理器中尝试过使用变量而带来的好处了,好比 Sass
和 Less
。
预处理器让你能设置变量,以及在函数、循环、数学计算等等地方中使用它们。这是否意味着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元素的其余颜色属性上,如 color
,border-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:
<--! HTML --> <html> <head> <!-- head code here --> </head> <body> <div> <p>blue 的段落</p> <div class="alert"> <p>red 的段落</p> </div> </div> </body> </html>
在上面的标签中,第一个段落会继承到全局的 --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 */ <svg> <symbol id="close-icon" viewbox="0 0 200 200"> <circle cx="96" cy="96" r="88" fill="none" stroke="var(--icon-color)" stroke-width="15" /> <text x="100" y="160" fill="var(--icon-color)" text-anchor="middle" style="font-size:250px;">x</text> </symbol> </svg> /* 图标的第一个实例 */ <svg> <use xlink:href="#close-icon" /> </svg>
上面的代码使用了 <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 代码:
<!-- html --> <div class="success"> <svg> <use xlink:href="#close-icon" /> </svg> </div>
如今,让 --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变量。经过 getComputedStyle
,setProperty
和 getPropertyValu
e从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的项目实战的学习资料都有整理
点击:加入