发布网友 发布时间:2024-10-02 15:06
共1个回答
热心网友 时间:2024-11-02 04:47
欢迎关注微信公众号: 前端侦探
介绍一个通过 CSS 变量自动更改样式的小技巧~
偶尔在网上看到这样一个设计,当阅读量比较少时,文字呈灰色,当阅读量比较多(>=100)时,文字就变成褐色了,示意效果如下
是不是非常醒目呢?
另外,还有那种可以根据进度自动变色的进度条,如下
其实通过纯 CSS 也能实现这样的逻辑判断,主要用到了 CSS 变量和边界值计算,现在分享一下
一、基本数学原理CSS 中并没有直接的 if 判断逻辑。要实现这样一种效果,必须充分利用 CSS calc 的计算特性和临界条件。
假设要实现这样一个逻辑:
--x默认值为 10,当变量--y大于等于 100 时,--x变为 20
如何实现呢?这里先给出答案,然后进行分析
--x:?clamp(10,(var(--y)?-?99)?*?99,20)这里用到了 clamp函数,你可以理解为一个区间,有 3 个值 [Min, Val, Max],前后分别是最小、最大值,中间是动态值,这里其实就是一个简单的线性函数,并且单调递增,所以这里的逻辑就是:
当--y小于 100 时,比如 99,(var(--y) - 99) * 99 的计算结果是 0,再小就是负数了,在 [10, 20] 区间中取较小值,所以最终结果是 10
当--y大于等于 100 时, 比如 100 ,(var(--y) - 99) * 99 的计算结果是 99,在 [10, 20] 区间中取较大值,所以最终结果是 20
用一张图表示如下
为什么这里需要乘以 99 呢?其实是一个放大插值的操作,严格来讲,这个例子中只要大于 20 就够了,当乘以 20 以后,范围就变成了 ?...、-20、0、 20、40、...,也是包含 [10, 20] 这个区间的。
这个就是CSS 中 if 判断的基本原理了,用到了一点点数*算,接下来看实战效果
二、通过饱和度变化首先简单布局一下
由于纯 CSS 无法获取到数值的大小,这里需要借助 CSS 变量进行计算,所以 HTML 可以这样
<num?style="--num:1">1<span>阅读</span></num><num?style="--num:99">99<span>阅读</span></num><num?style="--num:102">102<span>阅读</span></num>如果不考虑 HTML 语义或者 SEO 这类因素,这里的“数字”和“阅读”都可以通过伪元素来生成
num::before?{??counter-reset:?num?var(--num);??content:?counter(num);}num::after?{??content:?'阅读';}于是,HTML 可以进一步简化为
<num?style="--num:1"></num><num?style="--num:99"></num><num?style="--num:102"></num>简单修饰后效果如下
由于是灰色和褐色之前的变化,一种简单的方式是通过饱和度来控制,比如这里褐色的颜色是#aa540e,用 hsl 颜色表示就是 hsl(27, 50%, 36%),如下
这里饱和度可以控制颜色的鲜艳程度。饱和度越高,颜色越鲜艳,饱和度越低,颜色越暗淡,当饱和度降为 0,就变成彻底的灰色了,如下
所以,这里要实现两种颜色的切换,可以通过计算饱和度,具体规则就是
当 --num大于等于 100 时,饱和度为 85%,否则为 0%,利用前面一节的基本原理,所以实现就是
num{??--s:?clamp(0%,(var(--num)?-?99)?*?99%,85%);/*?>100?*/??color:?hsl(27?var(--s)?36%);}逻辑和前面一致,这就不重复了,实际效果如下
由于饱和度本身也有“阈值”,当饱和度低于 0% 时,仍然按照 0% 来渲染,所以上面实现可以去除最小值,简化后如下
num{??--s:?min((var(--num)?-?99)?*?99%?,85%);??color:?hsl(27?var(--s)?36%);}同样能达到相同的目的
三、完全颜色控制虽然饱和度变化控制比较容易,只需要控制一个参数就行了,但还是有些局限性。首先,这个灰色可能并不是设计师想要的灰色(实际可能会偏淡一点),再者,颜色变化不够自由,比如,默认是一个蓝色,超出一定数量后变成红色,这种就无法控制了。
于是,我们需要用完全解析的方式来实现,原理其实就对颜色的 3 个参数进行控制,rgb 或者 hsl都可以,假设两个颜色分别是rgb(29 125 250)和rgb(244 67 54),如下
这里不仅有递增的变化,也有递减的变化(比如,125 => 67、250 => 54),所以在 calc 计算的时候需要取反,具体实现如下
num{????--r:?clamp(29,?(var(--num)?-?99)?*?999?+?29?,?250);/*29,?250*/????--g:?clamp(67,?(var(--num)?-?100)?*?-999?+?67?,?125);/*128,?67*/????--b:?clamp(54,?(var(--num)?-?100)?*?-999?+?54?,?250);/*250,?54*/????color:?rgb(var(--r)?var(--g)?var(--b));}需要注意几点:
系数需要足够大,这里是 999,比如第一条,当 --num 为 100 时,如果系数是 99,那么计算的结果是 99 + 29,没有达到最大值 250,所以需要改大一点,比如 999
clamp 支持的参数必须是[min, val, max],min 和 max 不能对调,所以以上代码再实现时做了交换
实际效果如下
四、自动背景颜色变化虽然颜色可以通过上述方式进行自动变化,但是还是有些不足
代码量比较多,有些繁琐,容易混淆,特别是前后数字的顺序
只适用于两个颜色的变化,比如多种分段的颜色可能就无法实现了
背景相比于单纯的颜色来说,有一个非常大的优势在于多层叠加,如果控制每个背景的大小,不就可以控制最终展示的颜色了吗?
还是上面这个例子,我们先通过渐变绘制两层背景,上面是红色rgb(244 67 54),下面是蓝色rgb(29 125 250),然后通过
background-size来控制每一层的大小,原理是这样的
具体实现如下
num{??background:?linear-gradient(rgb(244?67?54),rgb(244?67?54)),?????linear-gradient(rgb(29?125?250),?rgb(29?125?250));??color:?#fff;??background-size:?calc(?(var(--num)?-?99)?*?100%?),?100%;}其实这个计算根据简单,解释一下:
当 --num 大于等于 100 时,计算结果肯定是大于 100% 的,所以上面的红色背景是可见的,整体表现为红色
当 --num 小于 100 时,计算结果肯定是小于等于 0% 的,即使是负数,background-size 也解析为 0%,所以上面的红色背景是不可见的,整体表现为下面的蓝色
实际表现如下
如果希望实现文字颜色的变化,可以利用到 background-clip
num{??background:?linear-gradient(rgb(244?67?54),rgb(244?67?54)),?????linear-gradient(rgb(29?125?250),?rgb(29?125?250));??color:?transparent;??background-size:?calc(?(var(--num)?-?99)?*?100%?),?100%;??-webkit-background-clip:?text;}是不是相比上面的方式简单了许多呢?
五、自动变色的进度条背景还可以适配多种颜色。接下来看一个文章开头的案例,实现这样一个可以自动变色的进度条,有这样几条规则:
当进度小于 30% 时,背景呈红色
当进度大于 30% 并且 小于 60% 时,背景呈橙色
当进度大于 60% 并且 小于 90% 时,背景呈蓝色
当进度大于 90% 时,背景呈绿色
示意如下
假设 HTML 如下
<div?class="bar"?style="--percent:?50;"></div>可以通过 CSS 伪类和计数器将 CSS 变量显示在页面,有兴趣的可以看看张鑫旭老师的这篇文章:小tips: 如何借助content属性显示CSS var变量值(这个案例也是在这个基础上修改的),简单修饰一下
<num?style="--num:1">1<span>阅读</span></num><num?style="--num:99">99<span>阅读</span></num><num?style="--num:102">102<span>阅读</span></num>0效果如下
那么该如何根据进度自动变色呢?
原理还是类似的!首先,还是将几个颜色通过渐变绘制出来,最后的颜色放在最前面,然后根据 CSS 变量控制背景尺寸就行了,原理示意如下:
由于background-size本身有边界*,当小于 0% 时,仍然按 0% 来渲染,所以这里可以不必用 clamp来加以*,减少代码量,具体代码实现是这样的
<num?style="--num:1">1<span>阅读</span></num><num?style="--num:99">99<span>阅读</span></num><num?style="--num:102">102<span>阅读</span></num>1简单看一下里面的逻辑:
当 --percent 大于 90 时,所有背景的尺寸都是 100%,自然显示最上层的绿色
当 --percent 大于 60 ,小于等于 90 时,只有最上层的绿色尺寸是 0,其他背景尺寸都是 100%,所以显示第二层的蓝色
当 --percent 大于 30 ,小于等于 60 时,上面两层背景尺寸都是 0,下面两层背景尺寸都是 100%,所以显示第三层的橙色
当 --percent 小于 30 时,只有最底层的尺寸是 100%,其他都是 0,所以显示最底层的红色
实际表现如下
背景自动变色已经实现了,不过数字还有一点小问题,当进度条比较小时,百分比数字明显放不下了,如下
所以,在这种情况下应该把百分比数字移到外面来,并且变成红色。
移到外面,可以通过text-indent属性来实现,文字颜色从白色变成红色(hsl(0,100%,50%)),可以通过亮度来实现,当亮度为 100% 时,任何颜色都会变成白色,由于亮度本身有*,当超过 100% 时,仍然按照 100% 来渲染,这一点可以利用起来,具体实现如下
<num?style="--num:1">1<span>阅读</span></num><num?style="--num:99">99<span>阅读</span></num><num?style="--num:102">102<span>阅读</span></num>2这里的计算原理也和前面一样,大家在这里可以仔细斟酌一下。
实际效果如下:
可以看到,当百分比小于 10 时,文字是在外部的,避免了空间不足的情况,非常智能。
完整代码可以访问:CSS auto color(codepen.io)
六、总结一下以上就是关于 CSS 自动变色技术的全部内容了,核心其实就是边界值的灵活计算,是不是非常强大呢?这里总结一下实现要点:
实现原理是 CSS 变量 和 calc 计算
clamp 可以*表达式的区间范围
通用核心代码 --x: clamp(10,(var(--y) - 99) * 99,20)
饱和度可以控制颜色的鲜艳程度,当饱和度为0,就变成灰色了
完全控制颜色变化,可以用 rgb 或者 hsl 完全表示出来,分别进行计算
以上方案仅适用于两个颜色的切换
多层背景叠加可以实现多种颜色切换
多层背景切换的核心在于背景尺寸的控制
亮度为 100% 时,颜色就变成了白色
部分属性本身有“阈值”,充分利用这种特性可以减少区域判断
当然,这种技术不仅仅适用于颜色的变化,只要是数值的变化都可以,比如文章中text-indent的切换,充分利用这些小技巧可以让我们的页面更加灵活,更加精致。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发???
欢迎关注微信公众号: 前端侦探
原文:https://juejin.cn/post/7103402278308675620