离谱!CSS 变量自动变色技术

发表于 2年以前  | 总阅读数:495 次

偶尔在网上看到这样一个设计,当阅读量比较少时,文字呈灰色,当阅读量比较多(>=100)时,文字就变成褐色了,示意效果如下 image-20220417223953275

是不是非常醒目呢?

另外,还有那种可以根据进度自动变色的进度条,如下

image-20220421195045775

其实通过纯 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],前后分别是最小、最大值,中间是动态值,这里其实就是一个简单的线性函数,并且单调递增,所以这里的逻辑就是:

  1. --y小于 100 时,比如 99,(var(--y) - 99) * 99 的计算结果是 0,再小就是负数了,在 [10, 20] 区间中取较小值,所以最终结果是 10
  2. --y大于等于 100 时, 比如 100 ,(var(--y) - 99) * 99 的计算结果是 99,在 [10, 20] 区间中取较大值,所以最终结果是 20

用一张图表示如下

image-20220422180943620

为什么这里需要乘以 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>

简单修饰后效果如下

image-20220417224108128

由于是灰色和褐色之前的变化,一种简单的方式是通过饱和度来控制,比如这里褐色的颜色是#aa540e,用 hsl 颜色表示就是 hsl(27, 50%, 36%),如下

image-20220421153927397

这里饱和度可以控制颜色的鲜艳程度。饱和度越高,颜色越鲜艳,饱和度越低,颜色越暗淡,当饱和度降为 0,就变成彻底的灰色了,如下

image-20220421154638527

所以,这里要实现两种颜色的切换,可以通过计算饱和度,具体规则就是

--num大于等于 100 时,饱和度为 85%,否则为 0%,利用前面一节的基本原理,所以实现就是

num{
  --s: clamp(0%,(var(--num) - 99) * 99%,85%);/* >100 */
  color: hsl(27 var(--s) 36%);
}

逻辑和前面一致,这就不重复了,实际效果如下

Kapture 2022-04-21 at 15.55.20

由于饱和度本身也有“阈值”,当饱和度低于 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),如下

image-20220421162109881

这里不仅有递增的变化,也有递减的变化(比如,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));
}

需要注意几点:

  1. 系数需要足够大,这里是 999,比如第一条,当 --num 为 100 时,如果系数是 99,那么计算的结果是 99 + 29,没有达到最大值 250,所以需要改大一点,比如 999
  2. clamp 支持的参数必须是[min, val, max]minmax 不能对调,所以以上代码在实现时做了交换

实际效果如下

Kapture 2022-04-21 at 16.43.24

四、自动背景颜色变化

虽然颜色可以通过上述方式进行自动变化,但是还是有些不雅

  1. 代码量比较多,有些繁琐,容易混淆,特别是前后数字的顺序
  2. 只适用于两个颜色的变化,比如多种分段的颜色可能就无法实现了

背景相比于单纯的颜色来说,有一个非常大的优势在于多层叠加,如果控制每个背景的大小,不就可以控制最终展示的颜色了吗?

还是上面这个例子,我们先通过渐变绘制两层背景,上面是红色rgb(244 67 54),下面是蓝色rgb(29 125 250),然后通过

background-size来控制每一层的大小,原理是这样的

image-20220421181904629

具体实现如下

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%;
}

其实这个计算根据简单,解释一下:

  1. --num 大于等于 100 时,计算结果肯定是大于 100% 的,所以上面的红色背景是可见的,整体表现为红色
  2. --num 小于 100 时,计算结果肯定是小于等于 0% 的,即使是负数,background-size 也解析为 0%,所以上面的红色背景是不可见的,整体表现为下面的蓝色

实际表现如下

Kapture 2022-04-21 at 18.19.56

如果希望实现文字颜色的变化,可以利用到 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;
}

Kapture 2022-04-21 at 18.29.38

是不是相比上面的方式简单了许多呢?

五、自动变色的进度条

背景还可以适配多种颜色。接下来看一个文章开头的案例,实现这样一个可以自动变色的进度条,有这样几条规则:

  1. 当进度小于 30% 时,背景呈红色
  2. 当进度大于 30% 并且 小于 60% 时,背景呈橙色
  3. 当进度大于 60% 并且 小于 90% 时,背景呈蓝色
  4. 当进度大于 90% 时,背景呈绿色

示意如下

image-20220421195045775

假设 HTML 如下

<div class="bar" style="--percent: 50;"></div>

可以通过 CSS 伪类和计数器将 CSS 变量显示在页面,有兴趣的可以看看张鑫旭老师的这篇文章:小tips: 如何借助content属性显示CSS var变量值[1](这个案例也是在这个基础上修改的),简单修饰一下

.bar {
  display: flex;
  height: 20px;
  background-color: #f5f5f5;
}
.bar::before {
  counter-reset: progress var(--percent);
  content: counter(progress) '%\2002';
  display: flex;
  justify-content: end;
  width: calc(var(--percent) * 1%);
  font-size: 12px;
  color: #fff;
  background: #2486ff;
  white-space: nowrap;
}

效果如下

image-20220421200829028

那么该如何根据进度自动变色呢?

原理还是类似的!首先,还是将几个颜色通过渐变绘制出来,最后的颜色放在最前面,然后根据 CSS 变量控制背景尺寸就行了,原理示意如下:

image-20220421223946629

由于background-size本身有边界限制,当小于 0% 时,仍然按 0% 来渲染,所以这里可以不必用 clamp来加以限制,减少代码量,具体代码实现是这样的

.bar::before{
  /*其他样式*/
  background-image: linear-gradient(green,green), 
    linear-gradient(#2486ff,#2486ff), 
    linear-gradient(orange, orange),  
    linear-gradient(red, red);
  background-size: calc( (var(--percent) - 90) * 100% ) 100%, 
    calc( (var(--percent) - 60) * 100% ) 100%,
    calc( (var(--percent) - 30) * 100% ) 100%,
    100% 100%;
}

简单看一下里面的逻辑:

  1. --percent 大于 90 时,所有背景的尺寸都是 100%,自然显示最上层的绿色
  2. --percent 大于 60 ,小于等于 90 时,只有最上层的绿色尺寸是 0,其他背景尺寸都是 100%,所以显示第二层的蓝色
  3. --percent 大于 30 ,小于等于 60 时,上面两层背景尺寸都是 0,下面两层背景尺寸都是 100%,所以显示第三层的橙色
  4. --percent 小于 30 时,只有最底层的尺寸是 100%,其他都是 0,所以显示最底层的红色

实际表现如下

Kapture 2022-04-21 at 23.00.00

背景自动变色已经实现了,不过数字还有一点小问题,当进度条比较小时,百分比数字明显放不下了,如下

image-20220421235719823

所以,在这种情况下应该把百分比数字移到外面来,并且变成红色

移到外面,可以通过text-indent属性来实现,文字颜色从白色变成红色(hsl(0,100%,50%)),可以通过亮度来实现,当亮度为 100% 时,任何颜色都会变成白色,由于亮度本身有限制,当超过 100% 时,仍然按照 100% 来渲染,这一点可以利用起来,具体实现如下

.bar::before{
  /*其他样式*/
  --l: max(50%, (var(--percent) - 9 ) * 100%);
  color: hsl(0, 100%, var(--l));
  --offset: clamp(0%, ( var(--percent) - 10 ) * -120% , 120%);
  text-indent: var(--offset);
}

这里的计算原理也和前面一样,大家在这里可以仔细斟酌一下。

实际效果如下:

Kapture 2022-04-21 at 23.46.59

可以看到,当百分比小于 10 时,文字是在外部的,避免了空间不足的情况,非常智能。

完整代码可以访问:CSS auto color(codepen.io)[2] 或者 CSS auto color(juejin.io)[3]

六、总结一下

以上就是关于 CSS 自动变色技术的全部内容了,核心其实就是边界值的灵活计算,是不是非常强大呢?这里总结一下实现要点:

  1. 实现原理是 CSS 变量 和 calc 计算
  2. clamp 可以限制表达式的区间范围
  3. 通用核心代码 --x: clamp(10,(var(--y) - 99) * 99,20)
  4. 饱和度可以控制颜色的鲜艳程度,当饱和度为0,就变成灰色了
  5. 完全控制颜色变化,可以用 rgb 或者 hsl 完全表示出来,分别进行计算
  6. 以上方案仅适用于两个颜色的切换
  7. 多层背景叠加可以实现多种颜色切换
  8. 多层背景切换的核心在于背景尺寸的控制
  9. 亮度为 100% 时,颜色就变成了白色
  10. 部分属性本身有“阈值”,充分利用这种特性可以减少区域判断

当然,这种技术不仅仅适用于颜色的变化,只要是数值的变化都可以,比如文章中text-indent的切换,充分利用这些小技巧可以让我们的页面更加灵活,更加精致。

参考资料

[1]小tips: 如何借助content属性显示CSS var变量值: https://www.zhangxinxu.com/wordpress/2019/05/content-css-var/

[2]CSS auto color(codepen.io): https://codepen.io/xboxyan/pen/ZEvZbzj

[3]CSS auto color(juejin.io): https://code.juejin.cn/pen/7091204180673003556

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/0smLo_3qjQu4nG8z60oxbA

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237269次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8108次阅读
 目录