头图

妙用 CSS 动画来实现颜色加深、减淡等混合操作

欢迎关注我的公众号:前端侦探

在上一篇 CSS 如何根据背景色自动切换黑白文字?中,讲述了文本自适应背景色的一些小技巧,不过还存在一定局限性,比如:如果是背景是渐变色该怎么办?

image.png

很容易想到的思路是将两个渐变色取过渡中间色,然后再通过前面的方式转换就行了

image.png

那么问题来了,有没有办法通过 CSS 实现中间颜色的获取呢?今天来一起探讨这个问题,聊一聊关于颜色合成的相关技巧。

一、你可能不知道 CSS 动画小技巧

想必大家都用过 CSS 动画,比如

@keyframes color {
  from {
    color: yellow
  }
  to{
    color: deeppink
  }
}
.text{
  animation: color 1s linear forwards;
}

这样就得到了一个颜色从yellowdeeppink的动画

Kapture 2022-12-28 at 15.49.54.gif

这个没什么好说的。

默认情况下,动画会播放 1 次后结束,然后设置了forwards,会保留在最后一帧状态。

那么,如果动画只播放一半,是不是就正好处于两者颜色的中间?其实,播放次数也可以是小数的,比如可以将播放次数设置为0.5次,就像这样

.text{
  animation: color 1s .5 linear forwards;
}

效果如下

Kapture 2022-12-28 at 15.56.58.gif

由于只播放了一半,所以到中间的橙色就停止了下来。

值得一提的是,通过这种方式得到的颜色,也是可以用 JS 去获取的

image.png

那么,利用这个特性,可以实现颜色的各种合成效果。

二、渐变背景下的文本自适应

回到前面的问题,如果是渐变背景,该如何实现自动切换黑白文字呢?

假设渐变的两种颜色分别是--c1--c2

<div class="box" style="--c1: #ffeb3b; --c2: deeppink">
  <span class="txt">前端侦探</span>
</div>

那么根据上一节的方法,可以将动画改造成这样

@keyframes color {
  from {
    color: var(--c1)
  }
  to{
    color: var(--c2)
  }
}

我们这里只是需要获取一下颜色,并不需要动画,所以可以将动画时长设置为很小的一个数,比如0.001s

.txt{
  animation: color .001s .5 linear forwards;
}

这样文字颜色就自动变成了渐变颜色的中间值,如下

image.png

然后再应用滤镜,将文字转换成黑色或者白色

.txt{
  animation: color .001s .5 linear forwards;
  filter: grayscale(1) contrast(9999) invert(1);
}

效果如下

image.png

也能完美适配任意渐变色

Kapture 2022-12-28 at 16.26.38.gif

完整代码可以查看以下任意链接

三、颜色的加深和减淡

再来看一个更加实用的例子,颜色的加深和减淡。通常用于主题色的生成,比如给定一个主题色,生成一系列和它相匹配的邻近色。下面是颜色逐渐减淡,最终变为白色的色阶图

image.png

根据上面的原理,可以很轻易的实现这样一个效果

假设 HTML 是这样的,每个方块给一个不同的 CSS 变量--l

<div class="box" style="--l:0"></div>
<div class="box" style="--l:0.2"></div>
<div class="box" style="--l:0.4"></div>
<div class="box" style="--l:0.6"></div>
<div class="box" style="--l:0.8"></div>
<div class="box" style="--l:1"></div>

然后创建一个从主题色到白色的动画,根据这个变量,让动画执行不同的次数

.box{
  animation: lighterBackgroundColor .001s var(--l) linear forwards;
}
@keyframes lighterBackgroundColor {
  from {
    background-color: var(--primary-color)
  }
  to{
    background-color: #fff
  }
}

这样就可以生成同种颜色,不同深浅度的主题色了

有同学可能会说像 sassless这些不也能实现吗?其实不然,这些都是预处理器,生成以后就不能再变了,而这种方式是实时绘制的,可以实现修改,如下

Kapture 2022-12-28 at 17.25.08.gif

完整代码可以查看以下任意链接

如果将这种技巧用到实际项目中也是非常完美,下面是不同主题色下的预览效果

image.png

选中背景色就是减淡80%后的颜色

.item.current{
  border-color: var(--primary-color);
  animation: lighterBackgroundColor .001s .8 linear forwards;
}

原理是完全相同的,这里就不详细介绍了,完整代码可以查看以下任意链接

除此之外,根据需求,还可以通过颜色透明度的变化来生成特定透明度的主题色

@keyframes OpacityBackgroundColor {
  from {
    background-color: var(--primary-color)
  }
  to{
    background-color: rgba(0,0,0,0)
  }
}

四、未来最期待的几个颜色处理函数

官方也看到了这种需求,因此在 CSS Color Module Level 5中起草了几个关于颜色合成的函数,这里简单介绍一下

首先是颜色混合color-mix,将两种颜色按照一定的比例进行融合

color-mix(in srgb, white, blue);

这表示whiteblue按照各自 50% 进行混合,最终会得到紫色rgb(50% 50% 100%)

如果要控制混合比例,可以这样

color-mix(in srgb, white 20%, blue);

还有一个叫做相对颜色relative color ,其实是对原有的颜色函数进行了补充,根据我的理解,可以将这个特性想象成 JS 中的解构赋值

hsl(from var(--accent) h s calc(l - 20%))

例如这个表示将颜色--accent分解成hsl三个变量,然后对其中的l,也就是亮度减少20%,也就达到了颜色变暗的目的

多么令人兴奋的特性!目前这两个特性仅在 safari 15+试验性功能开启支持(😂终于不拖后腿了)

image.png

五、总结一下

以上就是本文全部内容了,主要是利用 CSS 动画的过渡特性,间接达到了颜色混合的目的,下面是一些要点:

  1. CSS 动画的次数也能设置成小数,比如 0.5 表示动画只运行到一半
  2. 两个颜色的中间色就是颜色动画运行到一半的状态
  3. 颜色减淡可以看成是主题色到白色的动画,加深则是黑色
  4. 官方已经正在起草 CSS 颜色合成相关函数,目前仅 Safari 试验性支持

你学会了吗?总的来说,在color-mix到来之前,这样一个小技巧还算是不错的解决方案。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤

欢迎关注我的公众号:前端侦探

前端侦探
致力于有趣的前端探索~
13.3k 声望
13k 粉丝
0 条评论
推荐阅读
你可能不知道的dialog弹窗
想必大家都知道 HTML5 中有 dialog 这样一个标签,顾名思义,就是“弹窗”。除了有良好的语义外,随着浏览器的不断更新迭代,还出现了许多你可能不知道的特性,快速了解一下吧~

XboxYan8阅读 413

封面图
JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...

jenemy46阅读 5.9k评论 12

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木66阅读 6.1k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs39阅读 6.3k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木43阅读 7.3k评论 6

CSS 绘制一只思否猫
欢迎关注我的公众号:前端侦探练习 CSS 有一个比较有趣的方式,就是发挥想象,绘制各式各样的图案,比如来绘制一只思否猫?思否猫,SegmentFault 思否的吉祥物,是一只独一无二、特立独行、热爱自由的(&gt;^ω^&lt...

XboxYan43阅读 2.9k评论 14

封面图
从零搭建 Node.js 企业级 Web 服务器(二):校验
校验就是对输入条件的约束,避免无效的输入引起异常。Web 系统的用户输入主要为编辑与提交各类表单,一方面校验要做在编辑表单字段与提交的时候,另一方面接收表单的接口也要做足校验行为,通过前后端共同控制输...

乌柏木33阅读 6.2k评论 9

13.3k 声望
13k 粉丝
宣传栏