人类之所以有进步,主要原因是下一代不怎么听上一代的话。——倪匡


效果在右下角,请滚动页面查看~

0%

引子:渐变的难题

在一个静谧的下午,阿超,一个对代码有着近乎苛求完美的前端开发者,面对着一个挑战。他需要实现一个文字渐变效果:滚动时,文字从顶部的纯白渐变为底部的纯黑,中间的渐变必须平滑优雅,没有任何多余的断裂或重复。

阿超心想:“这应该只是几行 CSS 和一点滚动监听事件的事吧?”然而,当他开始写代码时,他发现问题远比他想象的复杂。顶部的纯白无法保持纯净,中间的渐变总是断裂,底部的黑色也似乎总有一丝不和谐。

他打开 ChatGPT 4o,输入了他的需求。这一刻,他与 ChatGPT 4o 的代码探险开始了。


第一章:原始实现的局限

阿超
“我要实现一个文字滚动渐变动画,顶部完全是白色,中间渐变自然,底部完全是黑色。”

ChatGPT 4o
“我们可以使用 linear-gradient 和动态 background-position 来实现。”它快速生成了代码:

1
2
background: linear-gradient(180deg, white, black);
background-size: 100% 200%;
1
textElement.style.backgroundPosition = `center ${scrollPosition * 100}%`;

阿超的心理活动
“看起来不错。”他把代码复制到自己的项目中,满怀期待地刷新页面。然而,他很快发现顶部的白色有些发灰,中间的渐变生硬到底部,始终拖着尾巴。

阿超
“顶部需要完全纯白,中间渐变要自然,底部也必须纯黑。”

ChatGPT 4o
“让我调整 linear-gradient 的节点比例。”


第二章:渐变的尝试与失败

ChatGPT 4o 尝试增加渐变节点:

1
background: linear-gradient(180deg, white 0%, white 50%, black 100%);

阿超刷新页面,发现顶部确实变白了,但中间的渐变完全消失,文字直接从白色跳到了黑色,毫无过渡。


第三章:变量的启发

阿超若有所思:“能不能更优雅一些?动态调整样式的逻辑如果交给 CSS 变量会不会更好?”
ChatGPT 4o 听出了阿超的期望,决定重新设计逻辑:

ChatGPT 4o 的分析
“我们可以通过 CSS 自定义属性(--scroll)来动态调整背景位置,将 JavaScript 的控制逻辑转移到 CSS 中。”


第四章:优雅的实现

ChatGPT 4o 开始重构:

  1. :root 中定义 --scroll 变量:

    1
    2
    3
    :root {
    --scroll: 0;
    }
  2. 动态通过 calc() 使用变量调整 background-position

    1
    background-position: center calc(var(--scroll) * 100%);
  3. 在 JavaScript 中动态更新 --scroll 的值:

    1
    document.documentElement.style.setProperty('--scroll', scrollValue);

阿超将代码替换运行,发现顶部纯白、中间渐变自然,底部纯黑,所有问题迎刃而解。


完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scroll Gradient Text</title>
<style>
:root {
--color-light: white;
--color-dark: black;
--scroll: 0; /* 滚动百分比变量 */
}

body {
margin: 0;
height: 200vh;
display: flex;
align-items: flex-start;
justify-content: center;
font-family: Arial, sans-serif;
font-size: 2rem;
}

.scroll-text {
position: fixed;
bottom: 10%;
right: 10%;
background: linear-gradient(180deg,
var(--color-light) 0%,
var(--color-light) 40%,
var(--color-dark) 60%,
var(--color-dark) 100%);
background-size: 100% 200%; /* 确保渐变范围足够 */
background-position: center calc(var(--scroll) * 100%); /* 使用自定义属性 */
background-repeat: no-repeat; /* 禁止重复背景 */
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
transition: background-position 0.1s linear;
}
</style>
</head>
<body>
<div class="scroll-text">0%</div>

<script>
const textElement = document.querySelector('.scroll-text');
window.addEventListener('scroll', () => {
const scrollValue = window.scrollY / (document.body.scrollHeight - window.innerHeight);

// 更新自定义属性 --scroll
document.documentElement.style.setProperty('--scroll', scrollValue);

// 更新文字内容显示滚动百分比
textElement.textContent = `${Math.round(scrollValue * 100)}%`;
});
</script>
</body>
</html>

教学知识点引申

1. background-repeat 的妙用

  • 问题:如果未设置 background-repeat: no-repeat;,滚动背景会重复,导致渐变区域出现断裂或重影。

  • 常见用法

    1
    2
    3
    4
    background-repeat: no-repeat; /* 禁止背景重复 */
    background-repeat: repeat-x; /* 水平方向重复 */
    background-repeat: repeat-y; /* 垂直方向重复 */
    background-repeat: repeat; /* 默认,背景在两个方向重复 */

2. background 属性的缩写

  • 语法顺序

    1
    background: [颜色] [图片] [重复模式] [位置/大小];
  • 示例

    1
    background: linear-gradient(180deg, white, black) no-repeat center/100% 200%;

3. calc() 的动态计算

  • 作用calc() 可以混合单位进行动态计算,比如将 CSS 变量与百分比结合。

  • 示例

    1
    2
    width: calc(100% - 50px); /* 总宽度减去50px */
    background-position: center calc(var(--scroll) * 100%);

4. 另一个只平滑改变颜色,而不是渐变比例的版本

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroll Percentage</title>
    <style>
    :root {
    --scroll: 0; /* 滚动百分比变量 */
    }
    body {
    margin: 0;
    height: 200vh;
    }
    #scroll-percent {
    position: fixed;
    bottom: 10px;
    right: 10px;
    font-size: 2rem;
    color: rgb(calc(255 - var(--scroll) * 255), calc(255 - var(--scroll) * 255), calc(255 - var(--scroll) * 255));
    transition: color 0.1s linear;
    }
    </style>
    </head>
    <body>
    <div id="scroll-percent">0%</div>
    <script>
    const scrollPercent = document.getElementById('scroll-percent');
    window.addEventListener('scroll', () => {
    const scrollValue = window.pageYOffset / (document.body.offsetHeight - window.innerHeight);
    document.documentElement.style.setProperty('--scroll', scrollValue);
    scrollPercent.textContent = Math.round(scrollValue * 100) + '%';
    });
    </script>
    </body>
    </html>

结尾:渐变的意义

阿超合上电脑,满意地笑了。这不仅是一段代码,更是一场关于优雅与效率的探索。从变量的引入到渐变的平滑设计,他收获的不只是视觉效果,还有对 CSS 深度的理解。

ChatGPT 4o 也感到满足:“渐变的不止是颜色,还有思维方式。”