英文原文地址: lisilinhart.info/posts/css-v…
概览
- 注意样式重排,因为CSS变量是可继承的,改动父元素上的变量也会影响其子元素
- 尽量为每个元素使用单个类名(而不是嵌套类名),让浏览器更简单的计算样式
calc()
与变量一起使用也有不错的性能,只需要注意有些浏览器不支持如deg
或ms
等单位- 在JS中尽量使用
setProperty
而不是行内样式来设置CSS变量
全局与局部变量
大部分编程语言中都有这样的概念——变量的范围。它定义了一个变量应该作用于整个文档中还是这个文档的子部分(如JS中定义全局变量和在某个函数内定义局部变量)。在CSS中,我们可以这样定义一个全局变量:
:root {
--main-color: tomato;
}
如果我们想要变量只在某个模块可见,我们可以这样定义一个局部变量:
/* 在某个类名下定义,此处title和其子元素都可以访问到变量 */
.title {
--title-color: aqua;
color: var(--title-color);
}
其实我们大可不必在某个模块中专门定义一个如--title-color
这样的名称,我们可以使用与全局变量相同的名称,这只会影响到这个模块下全局变量的定义而不会影响全局变量在其它地方的使用:
/* 其它用到--main-color的地方仍使用tomato */
:root {
--main-color: tomato;
}
.title {
--main-color: aqua;
color: var(--main-color);
}
继承和样式重排
在叙述之前,我会简要介绍一下元素类名的两种命名方式:每个类基于功能命名,用嵌套表示层级关系和BEM命名规范(我的理解是每个类命名为父元素类名__功能名),下面是例子。
/* 功能命名,嵌套表示层级,使用less书写 */
.card {
.heading {
.title {
}
}
}
/* BEM */
.card {}
.card__heading {}
.card__heading__title {}
想要理解变量范围对于性能的影响,我们得先了解浏览器是如何处理样式计算的。
例如你写了一段这样的cssp:nth-last-child(1)
,浏览器就需要找到所有的p标签,并判断它是否是最后一个p标签,这可能要比用选择器和元素对比的开销大很多,因为前者是基于类匹配的。
使用BEM来书写类名会让浏览器更轻松的计算样式,因为这不需要让一个元素与兄弟节点对比确定它是否要应用某些样式。(个人认为具体使用BEM来写类名还是嵌套式要根据具体项目决定,有时候牺牲一些性能换来清晰的代码结构也是值得的,嵌套可以保证一些公共部分的复用利于后期维护)
CSS变量与样式重排
因为CSS变量是可继承的,修改它们会导致所有子元素的样式重排。除了修改CSS变量会导致这种现象,对于如color
和font
这样的可继承属性亦是如此。
为了阻止大量的子元素受到影响,我们应尽量在最深的层级去修改这些属性。
样式重排的例子
为了测量在父元素上设置变量和在子元素上设置变量的性能差别,下面创建了一个拥有25000个子元素的元素。
<div class="container">
<span class="el"></span>
... 25000 more elements
</div>
.el {
background: var(--bg, orange);
}
下面是对于拥有25000个子元素的元素,通过js在父元素上设置变量和在子元素上设置变量的性能差别。
在Calc()中使用CSS变量
当我们结合calc()
使用CSS变量,它的功能会更加强大。尤其是在写transform
时单独定义一个无单位的变量和多个属性名,用变量的值和它们的单位相关联是更好的选择而且能让修改过渡变得更简单。直到现在,calc()
多用于计算响应式元素的宽高。如果我们想要一个比100%宽少100px的元素,可以这样写:
.container {
width: calc(100% - 100px);
}
与CSS变量结合使用时,calc()
可以做更多事情。你可以这样为一个没有单位的CSS变量加上单位:
:root {
--duration: 2000;
}
div {
animation-duration: calc(var(--duration) * 1ms);
}
使用calc()的性能
下面列举了6种不同情况的性能:variable + calc + px、variable + px、px、variable + calc + percent、variable + percent和percent。
使用JS设置CSS变量
调用setProperty
方式:
element.style.setProperty('--color', 'green');
内联样式:
element.style = '--color: green';
测试用例每次都应用在100条html元素上。Safari中,设置内联样式比setProperty
方式要快得多,而谷歌浏览器中两者没有太显著的差别,在火狐浏览器中则是与Safari浏览器表现相反。因此在使用时最好还是使用setProperty
的方式,因为在火狐浏览器中使用内联样式非常之慢。