css变量(自定义属性)
CSS变量与预处理器中的变量其实是不同的东西。
这些不同基于一个事实:CSS变量是浏览器中直接可用的CSS属性,而预处理中的变量是用于编译成常规的CSS代码,浏览器其实对它们一无所知。
这意味着,你可以在样式表中,在内联样式中,在SVG的标签中直接更新CSS变量,甚至可以在运行时用JavaScript直接修改它。而你是无法对预处理器中的变量做上面这些操作的。CSS变量开启了一个充满可能性的新世界大门。
不是说你必须要在两者间做出选择:没有什么东西限制你,你可以同时使用CSS变量和预处理变量,并享有它们各自带来的巨大好处。
语法:
官方的规范把它们称作作为级联变量的CSS自定义属性
在自定义属性前添加双横线前缀,然后像给普通CSS设值一样,给自定义属性设值。
:root { --my-cool-background: #73a4f4; }
#foo { background-color: var(--my-cool-background); }
上面的代码片段把--my-cool-background
这个自定义属性的作用域定义在:root
这个伪类中,这让该自定义属性能被全局访问到(即在<html>
标签内部的任何地方)。然后,使用val()
函数把ID为foo的容器的background-color
设置为自定义属性的值,这时该容器就有了浅蓝的背景色。
你还可以从通过利用CSS变量获得另一个CSS变量的值。例如:
--top-color: orange;
--bottom-color: yellow;
--my-gradient: linear-gradient(var(--top-color), var(--bottom-color));
最后,你可以在CSS变量中加入一个或多个备用值(fallback value/s),例如:
var(--main-color, #333);
上面的代码中,#333
是一个备用值。当自定义属性值无效或未指定(unset)时,如果这时也没有指定备用值,那么被继承的(inherited)属性值将会被使用。
CSS中原生的变量定义语法是:--*
,变量使用语法是:var(--*
),其中*表示我们的变量名称。关于命名这个东西,各种语言都有些显示,例如CSS选择器不能是数字开头,JS中的变量是不能直接数值的,但是,在CSS变量中,这些限制通通没有。
不能包含$,[,^,(,%等字符,普通字符局限在只要是“数字[0-9]”“字母[a-zA-Z]”“下划线_”和“短横线-”这些组合,但是可以是中文,日文或者韩文
/* 中文命名 */ :root{ --白色: #fff } .header { color: var(--白色) } /* 数字命名 */ :root{ --1: #fff } .header { color: var(--1) }
CSS变量是区分大小写的
与普通CSS属性不同,CSS变量是区分大小写的。
例如,var(--foo)
和var(--FOO)
是在求两个不同的自定义属性值,分别是--foo
和--FOO
的。
CSS变量受级联关系影响
和普通CSS属性一样,CSS变量是可继承的。例如,我们定义了一个属性,值为blue
:
:root { --main-color: blue; }
当你给任意在<html>
标签里的元素指定--main-color
变量时,它们都会继承到blue
这个值。
当你在另一个元素里,为改自定义属性设置了一个新值时,那么所有该元素的子元素都会继承那个新值。例如:
:root { --main-color: blue; } .alert { --main-color: red; } p { color: var(--main-color); } <--! HTML --> <html> <head> <!-- head code here --> </head> <body> <div> <p>blue 的段落</p> <div class="alert"> <p>red 的段落</p> </div> </div> </body> </html>
在上面的标签中,第一个p
段落会继承到全局的--main-color
值,它是蓝色。
在div标签中拥有.alert
类的段落会是红色,因为它的值继承自局部作用域里的--main-color
。
如何通过JavaScript操作CSS变量
另一个超级酷的事情就是,你可以直接通过JavaScript代码访问CSS变量。
假设在你的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
。
CSS变量的浏览器支持
除了IE11(它不支持CSS变量),所有主流浏览器都对CSS变量有全面地支持。
对于不支持CSS变量的浏览器,一个变通的方案是使用具有虚拟查询条件(dummy conditional query)的@supports
代码块:
section { color: gray; } @supports(--css: variables) { section { --my-color: blue; color: var(--my-color, 'blue'); } }
考虑到@supports
在IE/Edge里也起作用,上面的方法是可行的。如果你在val()
函数中使用了备用值,那么你的代码将更加可靠,它能在兼容性不好的浏览器中实现优雅降级。
对于上面的代码,在Chrome和其他支持CSS变量的浏览器中,<section>
标签里的文本将是蓝色:
在IE11中,由于它不支持CSS变量,页面将显示灰色文本:
此方法的一个缺点是,如果你大量使用CSS变量,而那些不支持CSS变量的浏览器在你的项目中有很高的适配优先级,那么相应的代码会变得很复杂,对于维护来说,甚至是噩梦。
在这种情况下,你可以选择使用带有cssnext的PostCSS,它能让你在CSS代码中使用最新的特性,并且让原本不支持这些属性的浏览器,也能运行这些代码(有点像JavaScript转换器做的事情)。