专栏名称: 奇舞精选
《奇舞精选》是由奇舞团维护的前端技术公众号。除周五外,每天向大家推荐一篇前端相关技术文章,每周五向大家推送汇总周刊内容。
目录
相关文章推荐
于小戈  ·  成年人的崩溃从父母生病开始 ·  13 小时前  
于小戈  ·  生个娃,被网暴了... ·  15 小时前  
槽值  ·  内娱欠她的,终于开始还了 ·  昨天  
槽值  ·  最没存在感的省,悄悄统治江浙沪 ·  4 天前  
51好读  ›  专栏  ›  奇舞精选

【动画进阶】酷炫的多行文本随滚动颜色变换

奇舞精选  · 公众号  ·  · 2024-10-31 14:44

正文

本文,我们来看这么个有意思的问题。使用 CSS,实现在页面屏幕中有一长串多行字母,现在需要随着页面滚动,改变每个字母的颜色。这也是掘金上一个同学的私信提问:

这里和这位同学细聊,他没有回复,有一个细节我没获取到,就是多行文本一开始是文字颜色是规律的还是不规律的,另外一个点,随着页面滚动,改变每个字母的颜色,需要有规律的改变,还是没有规律的改变?

这问题细琢磨,还是非常有意思的,效果的核心是:

  1. 多行文本,如何使用尽可能少的标签,让多行文本下的每一个字,呈现不一样的内容
  2. 随着改动,如何去控制每一个字颜色的改变?

带着这两个疑问,我们尝试使用 CSS 一步一步解决它!

单个标签实现多行文本下单个文字不同颜色

我们先来看,如何使用单个标签实现多行文本下单个文字不同颜色。这是之前在 【动画进阶】单标签下多色块随机文字随机颜色动画 [1] 讲解过的一个技巧。

看看如下效果:

停顿 10s,思考一下,如果仅仅使用一个标签,实现上面的效果,这是可能的吗?

这里,我们还可以利用内联元素的 background 展示特性来实现。

什么意思呢?其实 background 的展示,在 块级元素状态 内联元素状态 下的展示规则是不一样的。

表现为 display: inline 内联元素的 background 展现形式与 display: block 块级元素(或者 inline-block flex grid )不一致。

简单看个例子:

<p>Lorem .....p><a>Lorem .....a>

这里需要注意,

元素是 块级元素 ,而 内联元素

我们给它们统一添加上一个从绿色到蓝色的渐变背景色:

pa {
  backgroundlinear-gradient(90deg, blue, green);
}

看看效果:

什么意思呢?区别很明显:

  1. 块级元素的背景整体是一个渐变整体
  2. 内联元素的背景效果是以行为单位进行串连的,每一行都是会有不一样的效果,每行连起来整体组成一个完整的背景效果

基于这一点,我们同样可以实现单个 DIV 下的多重背景。

举个例子:

<div class="g-container">
    <span>ABCDEFGHIJKLspan>
div>
div {
    width300px;
}
span{
    color#000;
    font-size50px;
    line-height50px;
    letter-spacing25px;
    word-wrap: break-word;
    background#fc0;
}

此时,我们只设置了一个背景 background: #fc0 ,效果如下:

基于上面说的技巧,我们改造一下 background: #fc0 ,拆分成多段渐变背景:

span{
    //...
    backgroundlinear-gradient(
        90deg
        #fc0 0 25%
        #0f0 0 50%
        #000 75%
        #f00 0 100%
    );
}

这里,我们每隔 25%,设置了一段不同的颜色,如此一来,整个背景色就变成了 4 块:

基于这个技巧,我们同样可以封装一个 SCSS 函数,用于在单个 DIV 下生成多段色块。代码如下:

@use "sass:string";
@import url('https://fonts.googleapis.com/css2?family=Righteous&family=Ubuntu+Mono&display=swap');

$str: 'QWERTYUIOPASDFGHJKLZXCVBNMabcdefghigklmnopqrstuvwxyz123456789';
$lengthstr-length($str);


@function randomNum($max, $min: 0, $u: 1) {
    @return ($min + random($max)) * $u;
}
@function randomColor() {
    @return rgb(randomNum(20550), randomNum(255), randomNum(255));
}
@function randomLinear($count, $width) {
    $value: '';
    
    @for $i from 0 through ($count - 1) {
        $j: $i - 1;
        $value: $value + randomColor() + string.unquote(" #{$j * $width}px #{$i * $width}px,");
    }
    
    @return linear-gradient(90deg, string.unquote(#{$value}) randomColor() 0 100%);
}

span {
    backgroundrandomLinear(3650);
}

上面的代码,我们实现了一个 randomLinear($count, $width) 的 SCSS 函数,其中:

  1. $count 表示需要的色块个数
  2. $width 表示每个色块的宽度

如此一来,在一个 300px x 300px 的内联元素内,我们同样可以实现多个不同的随机颜色。利用这个技巧,一样可以实现单个平面下的随机文字随机颜色效果:

剩余的技巧都是相同的,这里就不再赘述,此技巧的完整代码,你可以戳这里: CodePen Demo -- Single Div Random Text And Random Color [2]

我们将上述技巧,运用在我们今天需要实现的效果之上。

假设,我们有如下一段多行文本:

<a>Lorem ipsum dolor sit amet consectetur adipisicing elit.?a>

效果如下:

image.png

我们只需要利用 inline display 的特性,利用渐变实现每个文字宽度下,不一样的颜色效果:

image.png

给上述效果,添加上 backgroug-clip: text color: transparent ,即可实现单个标签下,多行文本每个文字的颜色都不一样:

image.png

整个效果的核心, 就是如何利用渐变,给每个文字宽度下,设置不一样的颜色

基于滚动驱动动画,实现滚动下文字变色效果

下面,我们继续实现 基于滚动驱动动画,实现滚动下文字变色效果

当然,这里的滚动动作,只是实现动画效果的载体,其背后的本质还是基于上述效果下的文字变色。

这里也很好实现,我们有两种方式,基于上述效果实现文字变色效果:

  1. 利用 filter: hue-rotate() 动画,实现文字变色
  2. 利用 background-position 的位移动画,实现文字变色效果

两种方式,都可以实现,多行文本下,每个文字的颜色单独变色。

再不加入滚动驱动动画之前,我们首先实现多行文字的颜色变换。

上述效果的完整代码,目前是这样的:

<a>Lorem ipsum dolor sit amet consectetur adipisicing elit.?a>
@use "sass:string";

@function randomLinear($count, $width) {
    $value: '';
    
    @for $i from 0 through ($count - 1) {
        $j: $i - 1;
        $value: $value + randomColor() + string.unquote(" #{$j * $width}px #{$i * $width}px,");
    }
    
    @return linear-gradient(90deg, string.unquote(#{$value}) randomColor() 0 100%);
}

@function randomColor() {
    @return rgb(randomNum(20550), randomNum(255), randomNum(255));
}

@function randomNum($max, $min: 0, $u: 1) {
    @return ($min + random($max)) * $u;
}

a {
    width600px;
    font-size42px;
    line-height54px;
    font-family"Roboto Mono", monospace;
    backgroundrandomLinear(7225);
    background-clip: text;
    color: transparent;
}

这里唯一需要花时间理解的是 background: randomLinear(72, 25) 绘制的渐变图案。这里实现了一个 72 段长的渐变效果,每个渐变段的宽度是 25px

解释一下,由于我们单行的宽度是 600px ,所以 background: randomLinear(72, 25) 恰好可以实现一个铺满 3 行且每个文字宽度下色块颜色不一致的渐变效果。

接着,我们通过控制 background-position 的变换,实现文字颜色的切换,只需要加入如下的代码:

a {
    ...
    animation: colorChange 5s steps(18);
}

@keyframes colorChange {
    0% {
        background-position0 0;
    } 
    100% {
        background-position: -1800px 0;
    }
}

其中 72 * 25 = 1800 ,所以,我们利用 steps 步骤动画,实现一个渐变色块的位移动画(即 background-position 位移动画),运用到整个效果上,呈现出来的效果就是文字颜色的跳变:

有了这一步,接下来,我们只需要把动画效果,改为通过滚动动作控制即可,这里我们需要用到 CSS 最新的规范 -- 滚动驱动动画 -- animation-timeline [3] ,关于这个最新规范,你可以看看 XboxYan 老师的这篇文章,进行快速入门:

  • CSS 滚动驱动动画终于正式支持了\~ [4]

到这里,假设你对 滚动驱动动画 -- animation-timeline 已经掌握,我们只需要简单的改造上述的代码,给页面提供一个滚动动作,并且将动画关联上即可,修改我们的代码:

<div class="g-scroll">div>
<p><a>Lorem ipsum dolor sit amet consectetur adipisicing elit.?a>p>
@use "sass:string";
@import url('https://fonts.googleapis.com/css2?family=Carter+One&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Sofia+Sans&display=swap');

@function randomLinear($count, $width) {
    $value: '';
    
    @for $i from 0 through ($count - 1) {
        $j: $i - 1;
        $value: $value + randomColor() + string.unquote(" #{$j * $width}px #{$i * $width}px,");
    }
    
    @return linear-gradient(90deg, string.unquote(#{$value}) randomColor() 0 100%);
}

@function randomColor() {
    @return rgb(randomNum(20550), randomNum(255), randomNum(255));
}

@function randomNum($max, $min: 0, $u: 1) {
    @return ($min + random($max)) * $u;
}

bodyhtml {
    width100%;
    height100%;
    overflow: scroll;
    background#000;
    scroll-timeline-name: --my-scroller;
}

.g-scroll {
    height300vh;
}

p {
    position: fixed;
    display: inline;
    top50%;
    left50%;
    transformtranslate(-50%, -50%);
    margin: auto;
    width600px;
}
a {
    width600px;
    font-size42px;
    line-height54px;
    font-family"Roboto Mono", monospace;
    color#fff;
    backgroundrandomLinear(7225);
    background-clip: text;
    color: transparent;
    animation: colorChange steps(18);
    animation-timeline: --my-scroller;
}

@keyframes colorChange {
    0% {
        background-position0 0;
    } 
    100% {
        background-position: -1800px 0;
    }
}

上面是完整的代码,其实代码量非常少,添加的代码做了几件事:

  1. 文本效果,通过 fixed 定位到页面中心
  2. 添加了一个 300vh 高的容器,利用这个容器,触发 body 的滚动效果,并且给 body 设置了滚动容器 name scroll-timeline-name: --my-scroller
  3. a 标签下的动画,改成关联页面的滚动动作 animation-timeline: --my-scroller

这样,我们就实现了,在滚动过程中,改变多行文本的每一个字的颜色,并且,其核心效果,其实都是利用一个标签实现的:

完整的代码,你可以戳这里: CodePen Demo -- Text Color Change With Scroll [5]

当然,如果这样的效果都已经能够掌握了,那么想要实现规则的文字颜色的规则变换,也非常轻松。

我们改造一下代码,这次的渐变色不需要那么复杂:

<div class="g-scroll">div>
<p><a>Lorem ipsum dolor sit amet consectetur adipisicing elit.?a>p>
bodyhtml {
    width100%






请到「今天看啥」查看全文