hello!大家好!
shimmer text 是一种很常见的 CSS 文字高亮扫光效果:文字本身不动,一条亮色渐变从字形里扫过去,让它看起来像被光擦了一下。
你可能在 loading 文案、AI 正在生成的提示、产品首页 hero、价格标签里都见过它。效果很小,但如果写得舒服,页面会多一点“正在运行”的感觉。
现在 AI 已经能帮我们生成很多代码了,但我反而更觉得,一些基础技术还是值得自己弄懂。至少要做到**知其然!**看到一个 CSS 动效时,知道它大概由哪些属性拼起来,出了问题也知道从哪里拆。
所以这篇先不急着贴页面和仓库。我会先一步步拆 shimmer text 的原理:渐变怎么做出来,为什么能裁进文字,背景为什么要移动,倾斜高亮为什么还要算安全距离。
专门的教程页面和源码仓库我放在文末,读完原理以后再打开看,会更顺。
一般可以叫它:
shimmer text
text shimmer
gradient text shimmer
或者更直白一点:文字高亮扫光效果
它经常出现在这些场景里:
loading 状态里的文字或骨架屏;
AI 产品里“正在生成”的提示;
首页 hero 里的重点短句;
产品价格、功能标签、活动入口里的强调文案;
需要一点“正在运行”感觉的交互界面。
我个人会比较克制地用它。
因为 shimmer 很容易从“有质感”滑到“过度动效”。如果整个页面到处都在闪,用户的注意力会被拖着走,阅读会变累。我的倾向是:只在一个短句、一个状态、一个核心 CTA 周围使用它。
先把页面和工具放一边,单看这个效果本身。
它背后其实有三层东西:
文字本身;
一张比文字更宽的渐变背景;
把背景裁剪进文字形状的 background-clip:text。

这张图基本就是它的工作方式:小黑在后面推一条高亮带,文字像窗口一样,只露出背景穿过字形的那一部分。
先不考虑文字,也不考虑动画。
我们只需要一条渐变:
.shimmer {
background-image: linear-gradient(
80deg,
#8a8a8a,
#ffffff,
#8a8a8a
);
}
这一步只是准备材料。
#ffffff 是最亮的高光,左右两侧的灰色负责让它过渡得自然一点。shimmer 的质感,通常来自这个亮区的宽度:太宽会像一大片灯扫过去,太窄又会显得硬。
在 demo 里,我把高亮宽度做成了可调参数。这样读者可以直接看到:高亮区域越窄,效果越像一道光;高亮区域越宽,效果越像一块亮背景。
这里进入关键 CSS:
.shimmer {
color: transparent;
background-image: linear-gradient(
90deg,
#ff4d6d,
#ffd166,
#06d6a0,
#4cc9f0,
#8a5cf6
);
background-clip: text;
-webkit-background-clip: text;
}
这里有三个点要一起看:
color: transparent:把原本的文字填充色藏起来;
background-image:给文字背后放一张背景;
background-clip: text:只在文字字形范围里显示背景。

这时候读者看到的“字”,其实是背景图透过字形露出来的区域。
这里也有一个小坑。
如果你前面已经设置了 background-clip:text,后面又写了一次 background: ...,background 这个 shorthand 可能会把一些 background 相关属性重置掉。为了少踩坑,我更推荐在这个效果里使用 background-image,再单独写 background-size、background-position。
如果背景和文字一样宽,动画空间会很紧。
高亮带刚开始移动,就可能已经压在第一个字母上了。restart 的时候尤其明显:你以为动画会从最左侧外面进入,结果高亮一刷新就贴在文字上。
所以 demo 里用了:
.shimmer {
background-size: 400% 100%;
}
意思是:背景的宽度是文字可见区域的 4 倍。
这样高亮可以从文字左侧外面进入,穿过文字,再从右侧离开。文字本身不动,动的是这张更大的背景。
动画部分其实很短:
.shimmer {
animation: shimmer var(--speed) ease-in-out infinite both;
}
@keyframes shimmer {
0% {
background-position: var(--start-position) 0;
}
72%,
100% {
background-position: var(--end-position) 0;
}
}
重点是 background-position。
0% 是背景起点,72% 到 100% 是收尾段。后面留一点时间不继续移动,动画循环时会更稳,不会像机械循环一样马上跳回来。
这个处理很小,但体感明显。
我在 demo 里还加了 pause、restart 和 speed 控制。它们方便观察参数变化:当速度变慢、角度改变、宽度收窄时,背景移动的边界会变得更容易看出来。
做到这里,普通 shimmer 已经能跑了。
让我多花时间的是这个问题:
点击 restart 时,怎样让高亮真的从文字外侧进入?
如果高亮是水平的,事情还算直观。多留一点左右距离就行。
但这次我们希望高亮是 45deg 倾斜的。倾斜以后,高亮带会因为文字高度产生额外横向投影。说得直白一点:同样一条斜线,要保证它完全不碰到文字,就要比水平情况多留一些距离。
于是 demo 里算了一个 safeDistance:
const angle = 45 * Math.PI / 180
const safeDistance =
(shineWidth + textHeight * Math.abs(Math.cos(angle)) / 2)
/ Math.abs(Math.sin(angle))
这里不用把它想得太复杂。
我们只是根据:
高亮带宽度 shineWidth;
文字高度 textHeight;
高亮角度 angle;
算出一段额外的水平移动距离。

demo 里蓝色虚线和黄色安全范围就对应这个关系:蓝色范围表示文字可见区域,黄色范围表示高亮为了完整进出,需要额外走过的区域。
如果你把角度调得更斜,或者把高亮宽度调得更大,安全距离就会变大。这个关系可以用三角函数解释,实际工程里把它封装成一个计算函数就够了。
一份比较完整的最小版本大概是这样:
<p class="shimmer">CSS is awesome, right?</p>
<style>
.shimmer {
--speed: 2.4s;
--angle: 45deg;
--shine-width: 120px;
--start-position: 72%;
--end-position: 28%;
display: inline-block;
color: transparent;
font: 700 48px/1.1 system-ui;
background-image: linear-gradient(
var(--angle),
#8a8a8a calc(50% - var(--shine-width)),
#ffffff 50%,
#8a8a8a calc(50% + var(--shine-width))
);
background-size: 400% 100%;
background-position: var(--start-position) 0;
background-clip: text;
-webkit-background-clip: text;
animation: shimmer var(--speed) ease-in-out infinite both;
}
@keyframes shimmer {
0% {
background-position: var(--start-position) 0;
}
72%,
100% {
background-position: var(--end-position) 0;
}
}
</style>
如果只想做一个静态展示,这些就够了。
如果想像 demo 一样支持角度、宽度、restart、pause,就需要再加一点 JS,动态更新 CSS 变量。我的建议是:先把 CSS 版本跑通,再做控制器。不要一上来就把调参面板、localStorage、教程轮播全塞进去。
这个效果写起来不难,影响质感的是细节:
高亮不要太宽:短句里 2 个字母左右通常比较舒服。
角度不要乱跳:45deg 很稳定,识别度也好。
背景要足够大:background-size: 400% 100% 是一个好起点。
restart 要从外面进:不要只重置动画,还要确认 start-position 真的在文字外。
正文阅读场景慎用:长段落一直闪,读者会累。
我个人觉得,shimmer text 最适合放在“状态变化”附近。
比如 AI 正在生成、模型正在思考、结果即将出现。它传达的是一种轻微的进行中状态。放在纯装饰场景里也能看,但容易喧宾夺主。
这个小 demo 对我来说有一个挺有意思的点:很多 CSS 动效看起来像视觉技巧,拆开以后其实是几个很朴素的概念在配合。
linear-gradient() 做材料,background-clip:text 做裁剪,background-position 做移动,再用一点几何计算处理边界。
读者如果只想拿走一个结论,我会建议记住这句:shimmer text 的文字通常不动,动的是文字背后的背景。
先写到这里。后面如果我继续把这个 demo 做成更完整的 CSS 小课,可能会再补一篇,专门聊“如何把视觉效果做成可学习的交互说明”。
专门的教程页面在这里:
源码也放到了 GitHub:
这个页面一开始只是想复刻一个文本闪光效果,后来越做越像一个小教学工具:可以调速度、调高亮宽度、调角度,可以看完整背景,也可以看文字可见范围和计算后的安全范围。
