今天我学习了如何在 CSS(和 JavaScript)中制作文本渐变动画
🤔 ...🤔 ...🤔 ...
综上所述:
封面照片由 Clem Onojeghuo 拍摄,来自 Unsplash。
非常抱歉。不客气。
看看那糟糕的“咕噜咕噜”声。我感觉我的CPU都烧着了……可怜的家伙真是拼尽全力。我终于明白为什么CSS大佬们不让我这么做了。
第一部分:获取文本渐变
您可能会注意到代码的这一部分:
@mixin lead($one, $two, $three, $four, $five, $six) {
background: linear-gradient(80deg, $one, $two, $three, $four, $five, $six);
background-clip: text;
text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
这就是这场灾难中实际产生“彩虹文本”部分的原因。
这background
部分只是生成渐变本身;你可能以前在其他地方见过那种经典的彩虹效果。去掉那个 mixin 里的所有 和background-clip
,text-fill
它看起来就像这样:
所有其他的东西都使文本看起来像背景。
通常,background-clip 属性用于微调边框和填充等周围的背景外观,但“text”值非常神奇。
文本填充颜色大致相当于你的标准color
属性。(对于这支笔,你也可以轻松地替换它color: transparent
,我试过了,确实有效。)在这种情况下,我们可以将其设置为“透明”,这样我们的背景就会透过来。
那么,获取“彩虹文本”的步骤如下:
- 背景变成了彩虹
- 背景被剪裁,因此唯一显示的部分是通常被文本覆盖的部分
- 文本是透明的,所以我们可以透过它看到背景
第二部分:你可以为背景添加动画,但不能使其成为线性渐变
一切从这里开始变得脱轨。我最初的方法是直接把一个渐变贴transition
在一个容器上,然后就完事了;这大概需要五分钟,而且大部分时间都用来在谷歌上搜索如何让渐变与背景贴合。
然而
是时候尝试另一种策略了。
<div id="main" class="container lead-red">
HAPPY PRIDE MONTH
</div>
<div id="fade" class="container lead-orange">
HAPPY PRIDE MONTH
</div>
等等,为什么有两个-
🤔
function intervalFunction() {
rainbowify();
setTimeout(intervalFunction, getNextTimeoutDuration());
};
intervalFunction();
你在间歇期做什么?
🤔 ...🤔 ...🤔 ...
哦不。
要点如下:
让两个几乎相同的 HTML 元素相互重叠。第一个元素#main
位于底层,始终可见;它在渐变之间以恒定的不透明度“闪烁”。第二个元素#fade
位于顶层,始终闪烁(对齐时)和淡出(使用 实现过渡效果opacity
)。
这两个元素并不在同一个“彩虹周期”上——#fade
文本的颜色比 的颜色要早一种#main
。JavaScript 使用 setInterval 循环来调整这两个元素的类,以保持颜色的动态变化。
那也没有用。
第三部分:闪烁,淡出
我的代码大致如下:在主 setInterval 循环中,尝试使用一个.halt
将 transition-timing 属性设置为 0ms 的类来暂停动画(实际上禁用了过渡效果)。然后,我将不透明度设置为 1,使其“闪烁”,并移除该类.halt
。之后,我将不透明度重新设置为 0,让过渡效果发挥它的魔力。这一切立即完成,只用了大约四行代码。
其实,CSS 过渡并非如此。事实上,为了实现过渡,渲染引擎需要几毫秒的时间来完成所有操作,无论当时元素上的 transition 属性是什么。
事实证明,几乎立即添加然后删除一个类是不够的。
我尝试过一段时间的过渡时间和其他 CSS,最后放弃了,转而尝试 JavaScript。最初的 JS 技巧是setTimeout( ... , 20)
在现有的 setInterval 循环中使用一个,大约 95% 的情况下都有效。如果设置较低的超时时间,过渡效果会因为跟不上而出现卡顿;如果设置较高的超时时间,动画中会出现非常明显的停顿。然而,我并不想让这些奇怪的魔法数字和 Blinky McBlinkerton 的偶尔造访搞砸……
第四部分:减少抖动
我首先想消除的是那个神奇的 20ms 超时。我在 Google 上搜索了很久,终于找到了这个:
这解释了这一点:
fade.classList.add("halt");
fade.classList.add("hide");
fade.classList.remove("lead-" + rainbow[(i + 1) % ilen]);
fade.classList.add("lead-" + rainbow[(i + 2) % ilen]);
void fade.offsetWidth; // <- this one!
fade.classList.remove("halt");
fade.classList.remove("hide");
我觉得接下来要提前考虑的怪事是JS 计时器漂移。我以前在构建时间表和时钟时就遇到过这种情况;指定的 1 毫秒在现实中并不总是1 毫秒,因此任何间隔都不可避免地会越来越偏离准确度。由于我的 SCSS 和 JS 代码中硬编码了相同的超时时间,如果它们能够保持一致,效果肯定会更好。这可以防止因计时器漂移而导致的进一步停顿、卡顿等问题。
为此,我使用 setTimeout 而不是 setInterval,并让超时函数调用另一个函数,该函数再调用另一个超时函数(实际上是在超时函数之外创建一个间隔)。每次超时都会记录其开始时间,并记录与上次超时之间的“偏差”,然后进行自我修正,以更准确地达到长期目标。如果我要转向类似这样的方法,这绝对会很有用@keyframes
。
综上所述:
这太复杂了,而且运行起来像冬天的糖蜜一样慢。做个动图什么的就好了。
(预计到达时间:请在此处跟进。如果出于某种原因您确实想这样做...)
但我做到了,CSS 霸主们。我打败了你们。我胜利了。
文章来源:https://dev.to/tchaflich/today-i-learned-how-to-animate-a-text-gradient-in-css-and-javascript-2ehp