4、完美极致的变量
「变量」又名「自定义属性」,指可在整个文档中重复使用的值。它由自定义属性--var
和函数var()
组成,var()
用于引用自定义属性。使用变量能带来以下好处。
- 减少样式代码的重复性
- 增加样式代码的扩展性
- 提高样式代码的灵活性
- 增多一种CSS与JS的通讯方式
- 不用深层遍历DOM改变某个样式
同时变量也是浏览器原生特性
,无需经过任何转译可直接运行,也是DOM对象,极大便利了CSS与JS间的联系。变量除了具备简洁性和复用性,在重构组件样式时能让代码更易控制,同时还隐藏了一个强大的技巧,那就是与calc()
结合使用。
看看一个简单的例子。一个条形加载条通常由几条线条组成,每条线条对应一个存在不同时延的相同动画,通过时间差运行相同动画,从而产生加载效果。估计大部分同学可能会把代码编写成以下形式。

<ul class="strip-loading">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
.strip-loading {
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 200px;
li {
border-radius: 3px;
width: 6px;
height: 30px;
background-color: #f66;
animation: beat 1s ease-in-out infinite;
& + li {
margin-left: 5px;
}
&:nth-child(2) {
animation-delay: 200ms;
}
&:nth-child(3) {
animation-delay: 400ms;
}
&:nth-child(4) {
animation-delay: 600ms;
}
&:nth-child(5) {
animation-delay: 800ms;
}
&:nth-child(6) {
animation-delay: 1s;
}
}
}
@keyframes beat {
0%,
100% {
transform: scaleY(1);
}
50% {
transform: scaleY(.5);
}
}
分析代码发现,每个<li>
只是animation-delay
不同,其余代码则完全相同,换成其他类似的「List集合」,那岂不是有10个<li>
就写10个:nth-child(n)
。显然这种方式不灵活也不易封装成组件,若能像JS那样封装成一个函数,并根据参数输出不同样式效果,那就更棒了。
对于HTML部分的修改,让每个<li>
拥有一个自己作用域下的变量。对于CSS部分的修改,就需分析哪些属性是随着index
递增而发生规律变化的,对规律变化的部分使用变量表达式代替即可。当然以下<li style="--line-index: n;"></li>
可用React JSX
或Vue Template
的遍历语法编写。
<ul class="strip-loading">
<li style="--line-index: 1;"></li>
<li style="--line-index: 2;"></li>
<li style="--line-index: 3;"></li>
<li style="--line-index: 4;"></li>
<li style="--line-index: 5;"></li>
<li style="--line-index: 6;"></li>
</ul>
.strip-loading {
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 200px;
li {
--time: calc((var(--line-index) - 1) * 200ms);
border-radius: 3px;
width: 6px;
height: 30px;
background-color: #f66;
animation: beat 1.5s ease-in-out var(--time) infinite;
& + li {
margin-left: 5px;
}
}
}
@keyframes beat {
0%,
100% {
transform: scaleY(1);
}
50% {
transform: scaleY(.5);
}
}
代码中的变量--line-index
和--time
使每个<li>
拥有一个属于自己的作用域。例如第二个<li>
,--line-index
的值为2,--time
的计算值为200ms
,换成第三个<li>
后这两个值又会不同了。这就是变量的作用范围所致(在当前节点块作用域及其子节点块作用域下有效
)。
calc(var(--line-index) * 200ms)
就像一个JS函数,在当前节点的作用域上读取相应的变量,从而计算出具体数值并交由浏览器初始化。从中可得出一个技巧:「List集合里具备与索引递增相关的属性值都可用变量与calc()
结合使用生成出来」。
还记得小学时代学习圆周率的场景吗,曾经有学者将一个圆形划分为很多很小的矩形,若这些矩形划分得足够细,那么也可拼在一起变成一个圆形。
将圆形划分为360个小矩形且每个矩形相对于父容器绝对定位,声明transform-origin
为center bottom
将小矩形的变换基准变更为最底部最中间
,每个小矩形按照递增角度顺时针旋转N度,就会形成一个圆形。此时按照递增角度调整小矩形的背景色相,就会看到意想不到的渐变效果了。
- 每个小矩形的递增角度:
--Θ:calc(var(--line-index) / var(--line-count) * 1turn)
- 每个小矩形的背景色相:
filter:hue-rotate(var(--Θ))
- 每个小矩形的旋转角度:
transform:rotate(var(--Θ))
若将小矩形的尺寸和数量设置更细更多,整体的渐变效果就会更均匀。
<ul class="gradient-circular" style="--line-count: 360;">
<li style="--line-index: 1;"></li>
...
<li style="--line-index: 360;"></li>
<!-- 360个<li>,可用模板语法生成 -->
</ul>
.gradient-circular {
position: relative;
width: 4px;
height: 200px;
li {
--Θ: calc(var(--line-index) / var(--line-count) * 1turn);
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: #3c9;
filter: hue-rotate(var(--Θ));
transform-origin: center bottom;
transform: rotate(var(--Θ));
}
}

请登录后发表评论
注册
社交帐号登录