8 个硬核技巧带你迅速提升 CSS 技术<4>

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 JSXVue 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-origincenter 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(--Θ));
    }
}
© 版权声明
THE END
喜欢就支持以下吧
点赞1赞赏 分享
吐槽 抢沙发

请登录后发表评论