头图

妙用 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到来之前,这样一个小技巧还算是不错的解决方案。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤

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

前端侦探
致力于有趣的前端探索~
14.6k 声望
13.7k 粉丝
0 条评论
推荐阅读
原生popover终于来了!
欢迎关注我的公众号:前端侦探提到 popover,相信大家都很熟悉,没错,就是组件库里经常见到的悬浮层(或者叫“气泡卡片”),比如 Ant Design现在,这个好用的特性终于在Chrome 114上正式支持了~下面花几分钟快速...

XboxYan3阅读 1

封面图
涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco20阅读 2k评论 2

在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 1.9k

封面图
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!

SegmentFault思否20阅读 5.6k评论 10

封面图
你可能不需要JS!CSS实现一个计时器
CSS现在可不仅仅只是改一个颜色这么简单,还可以做很多交互,比如做一个功能齐全的计时器?样式上并不复杂,主要是几个交互的地方数字时钟的变化开始、暂停操作重置操作如何仅使用 CSS 来实现这样的功能呢?一起...

XboxYan20阅读 1.5k评论 1

封面图
「彻底弄懂」this全面解析
当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在 哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this就是记录的其中一个属性,会在 函数执行的过程中用到...

wuwhs17阅读 2.4k

封面图
学会这些 Web API 使你的开发效率翻倍
随着浏览器的日益壮大,浏览器自带的功能也随着增多,在 Web 开发过程中,我们经常会使用一些 Web API 增加我们的开发效率。本篇文章主要选取了一些有趣且有用的 Web API 进行介绍,并且 API 可以在线运行预览。C...

九旬13阅读 1.5k

封面图
14.6k 声望
13.7k 粉丝
宣传栏