前言
最近有个需求,和这个很像,但是又不完全一样
这个是chokcoco 老师的作品【Web动画】科技感十足的暗黑字符雨动画
问题
大佬的解决方案很好,但是在我们的实际场景中,会有点不足。
当我们的背景不再是黑色或者说不再是纯色的时候,通过遮罩来控制文字颜色的方法就会显示弊端。
看例子:
会出现色条。
由于我们遮罩的这个条算是要上下移动的,而且背景如果是图片的话,背景颜色会更加的复杂,所以也很难通过渐变什么的手段来做颜色上的适配。
所以我们现在的核心问题其实就是,还有没有什么方法,能让一行文字有不同的颜色表现。
background-clip
background-clip
是一个 CSS 属性,用于指定背景图片或颜色的绘制区域。它决定了背景图片或颜色的绘制范围,可以是整个元素、边框盒、内边距框或者文字区域。
这个属性接受以下几个值:
border-box
:默认值。背景将被绘制到边框盒的内边距框之下。padding-box
:背景将被绘制到内边距框之内,而不包括边框区域。content-box
:背景将被绘制到内容框的内部,而不包括内边距和边框区域。text
:背景将被绘制到文本内容的区域内,背景将被剪切成文字的形状。no-clip
:背景将被绘制到整个元素的区域内,不进行剪裁。
我们这里是为了让文字变色,所以我们将这里的值设置为text
。
看一下实际效果:
这里我们的实现原理就是:
- 设置
color: transparent
和background-clip: text
让文字的颜色为背景的颜色,同时把背景的颜色隐藏了 - 再通过动画设置background-position,来改变文字的颜色
这种做法本质上并没有什么不一样,只是通过background-clip: text
把背景的颜色和文字的颜色结合在一起,这样就不会有色条的出现。
这种方法有点缺陷,因为设置了color: transparent
,所以可能会有一瞬间,文字的颜色是隐藏了的,但是通过调整颜色和动画,它的影响可以被缩小。
代码
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
padding-top: 50px;
}
.container {
width: 100px;
height: 600px;
background: linear-gradient(blue, yellow 100%);
display: flex;
justify-content: center;
position: relative;
}
.text {
width: 30px;
text-align: center;
height: 100%;
position: relative;
font-size: 30px;
background-position: 0 -300px;
background-size: 100% 100%;
background-repeat: no-repeat;
background: linear-gradient(
transparent 0,
rgba(12, 249, 182, 0.9) 30%,
transparent 75%,
blue
);
background-clip: text;
color: transparent;
font-weight: bold;
word-break: break-all;
animation: move 2s infinite linear;
}
@keyframes move {
0% {
background-position: 0 -300px;
}
20% {
background-position: 0 -300px;
}
100% {
background-position: 0 700px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="text">这是一个寂寞的天, 下着有些伤心的雨</div>
</div>
</body>
<script></script>
</html>
mix-blend-mode
第二种方法是还是利用遮罩的手段,只是我们对遮罩后的背景颜色加了混合。
目的是消除遮罩层与原有底层由于色差而出现的色块。
mix-blend-mode
是一个 CSS 属性,用于控制元素的背景与其背后元素的混合方式。这个属性允许你通过不同的混合模式来创建各种视觉效果,比如透明、叠加、差值等。
我们可以看一下上面的动图,我们在设置好了渐变的背景色,和黑色的渐变遮罩层后,通过添加不同的mix-blend-mode的属性值,就能有不同的表现形式。
这里我们可以看见取值为lighten 和screen的时候,表现会好一点。
但是这个不是绝对的,和我们所使用的颜色搭配有很大的关系。
下面是一些属性值的含义:
screen
:将两个颜色值的相反值相乘得到结果,产生一个较亮的混合色。类似于叠加一个半透明白色图层。overlay
:根据底层色调调整顶层色调的混合模式。如果底层色较亮,则会加深顶层色的颜色,如果底层色较暗,则会减淡顶层色的颜色。darken
:将两个颜色值进行比较,保留较暗的颜色。lighten
:将两个颜色值进行比较,保留较亮的颜色。difference
:将两个颜色值进行比较,产生一个反差的混合色。color-dodge
:根据底层色进行颜色减淡。
这个方法相对于上一种方法,优点在于,调试的好的话,几乎是完美的。
那么缺点就是,需要大量的调试颜色以及属性值,如果调试不好的话,那么还是会出现色块。
这是最终效果:
代码
js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
width: 100px;
height: 600px;
background: linear-gradient(blue, yellow 100%);
display: flex;
justify-content: center;
position: relative;
}
.text {
width: 30px;
text-align: center;
height: 100%;
position: relative;
font-size: 30px;
background-position: 0 0px;
background-size: 100% 100%;
background-repeat: no-repeat;
mix-blend-mode: screen;
color: rgb(12, 249, 182);
font-weight: bold;
word-break: break-all;
}
.text::before {
content: '';
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background: linear-gradient(
rgba(0, 0, 0, 0.9),
transparent 75%,
transparent
);
background-size: 100% 100%;
background-repeat: no-repeat;
animation: move 2s infinite linear;
}
@keyframes move {
0% {
background-position: 0 -300px;
}
20% {
background-position: 0 -300px;
}
100% {
background-position: 0 600px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="text">这是一个寂寞的天, 下着有些伤心的雨</div>
</div>
</body>
<script></script>
</html>
总结
在复杂背景情况下,想要做到文字完美的变色,需要结合实际情况和一定工作量的调试,借助background-clip 或者mix-blend-mode,还是很有希望能调试出来完美效果的。