
写在前面昨天我们做了一只拟物怀表——金属、皮革、厚度都是“实体”的质感。今天做两个“笔画级”的文字效果流光文字——标题里一道光带缓慢扫过像金属或玻璃在反光手写签名——签名像被“画”出来一样一笔一笔出现、停笔、再被擦掉、循环看起来是两个不相干的效果其实本质完全一样都是“让一段渐变 / 线条按进度展示”。流光让“一段高光渐变”按进度扫过签名让“一条SVG路径”按进度画出来理解了这个统一视角你就能把这两个效果都拆到最简单。一、先看效果深色卡片上从上到下三件事顶部衬线大字「AURUM」——金属灰字面里一道蓝白光带每4.2秒从右往左扫过中部一条蓝色曲线凭空起笔游走转折像在签某个花体名字收笔后一道绿色下划线补上底部停两秒笔画像被橡皮擦反向擦掉再重新写起签名的完整循环约6.5秒——写 → 停 → 擦 → 再写。怎么跑起来新建一个demo.html把下面第二节的完整代码粘进去双击用浏览器打开截图党提示录7秒GIF抓签名完整循环最生动——静态图看不出“书写”这个过程。如果只能截图选签名写到2/3的瞬间——笔画悬在半空最能暗示“正在写”。二、完整代码复制即用!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8metanameviewportcontentwidthdevice-width, initial-scale1.0titleDay 19 · 流光文字与手写签名/titlestyle*{margin:0;padding:0;box-sizing:border-box;}html, body{height:100%;}body{display:flex;align-items:center;justify-content:center;overflow:hidden;background:#10151c;font-family:PingFang SC,sans-serif;}.card{width:min(560px,92vw);padding:52px 48px 44px;border-radius:18px;background:#131a23;border:1px solidrgba(255,255,255,.07);box-shadow:0 30px 70pxrgba(0,0,0,.45);text-align:center;}.label{font:400 10px/1SF Mono,Consolas,monospace;letter-spacing:.34em;color:#5b6878;}/* —— 流光文字渐变裁进字形高光带横扫 —— */.shine{margin-top:30px;font-family:Georgia,Times New Roman,serif;font-size:64px;font-weight:600;letter-spacing:.18em;background:linear-gradient(110deg,#5a6472 0%,#5a6472 38%,#f2f6fb 47%,#9fd6ff 53%,#5a6472 62%,#5a6472 100%);background-size:250% 100%;-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent;animation:sheen 4.2s linear infinite;}keyframessheen{from{background-position:250% 0;}to{background-position:-250% 0;}}.divider{width:64px;height:1px;background:rgba(255,255,255,.12);margin:30px auto 6px;}/* —— 手写签名SVG stroke 描边写完停笔、再被擦掉、循环 —— */.sig{display:block;width:min(420px,78vw);margin:0 auto;overflow:visible;}.stroke{fill:none;stroke-linecap:round;stroke-linejoin:round;}.s1{stroke:#9fd6ff;stroke-width:3.5;stroke-dasharray:900;stroke-dashoffset:900;animation:draw1 6.5s ease-in-out infinite;}.s2{stroke:#5cc9b4;stroke-width:3;stroke-dasharray:420;stroke-dashoffset:420;animation:draw2 6.5s ease-in-out infinite;}keyframesdraw1{0%{stroke-dashoffset:900;}30%{stroke-dashoffset:0;}72%{stroke-dashoffset:0;}100%{stroke-dashoffset:-900;}}keyframesdraw2{0%, 16%{stroke-dashoffset:420;}42%{stroke-dashoffset:0;}74%{stroke-dashoffset:0;}100%{stroke-dashoffset:-420;}}.note{margin-top:26px;font:400 10px/1SF Mono,Consolas,monospace;letter-spacing:.3em;color:#39434f;}.tag{position:fixed;right:18px;bottom:14px;font:400 10px/1SF Mono,Consolas,monospace;letter-spacing:.28em;color:rgba(230,237,243,.22);}/style/headbodydivclasscarddivclasslabelSIGNATURE STUDY · DAY 19/divdivclassshineAURUM/divdivclassdivider/divsvgclasssigviewBox0 0 420 140pathclassstroke s1dM20 96 C 60 20, 92 18, 96 62 C 99 92, 76 108, 62 100 C 50 93, 66 74, 96 72 C 150 68, 168 40, 196 44 C 226 48, 214 88, 246 84 C 282 79, 288 46, 318 52 C 344 57, 340 84, 368 78 C 386 74, 396 60, 404 48/pathclassstroke s2dM26 116 C 120 130, 260 126, 398 104//svgdivclassnoteBACKGROUND-CLIP:TEXT STROKE-DASHOFFSET/div/divdivclasstag每天一个惊艳 CSS · DAY 19/div/body/html三、三个核心技法拆解代码不长但每一个技法都值得单独拿出来讲——它们不是“这个效果专属”而是通用工具。技法1background-clip: text把渐变「灌进」字形流光文字的核心思路你想一下——不是“文字在发光”而是——“一道光带扫过文字的表面**。”**所以本质是“渐变在动”文字只是“渐变的容器”。.shine{/* ① 文字本身的颜色 → 透明 */color:transparent;-webkit-text-fill-color:transparent;/* ② 背景是一段“三段式”渐变 */background:linear-gradient(110deg,#5a6472 0%,/* 基色 */#5a6472 38%,/* 基色 */#f2f6fb 47%,/* 高光带 —— 从暗到极亮 */#9fd6ff 53%,/* 高光带 —— 从极亮到蓝 */#5a6472 62%,/* 基色 */#5a6472 100%);/* 基色 *//* ③ 背景放大到250%光带才有空间滑动 */background-size:250% 100%;/* ④ 关键把背景“裁剪”到文字的笔画里 */-webkit-background-clip:text;background-clip:text;/* ⑤ 动画只扫background-position */animation:sheen 4.2s linear infinite;}keyframessheen{from{background-position:250% 0;}to{background-position:-250% 0;}}逐条理解① 文字颜色透明——这是“让背景透出来”的前提color:transparent;/* 通用 */-webkit-text-fill-color:transparent;/* Safari / 老Chrome需要 */两行都要写——这是 Safari 的历史遗留。只写color: transparent在Safari里会“露底”显示出默认的黑色文字。②background-clip: text—— 让背景只从字形里透出来这是整个效果的核心属性——它把“元素的矩形背景”裁成“文字笔画的形状”。结果渐变不再覆盖整块矩形而是只出现在文字的笔画里。③background-size: 250% 100%—— 给光带留出“滑动空间”默认background-size: 100%——渐变正好铺满元素没有“藏起来的部分”也就没法扫。放大到250%——渐变比元素宽2.5倍——光带可以从外面扫进来、再扫出去。④ 动画只扫background-positionkeyframessheen{from{background-position:250% 0;}/* 光带在“很远的右边” */to{background-position:-250% 0;}/* 光带扫到“很远的左边” */}从250%扫到-250%——光带完整地穿过文字从头到尾扫一遍。为什么首尾都停在基色#5a6472因为渐变的0% ~ 38%和62% ~ 100%都是基色——所以光带在起点250%时——可见区域是基色光带在终点-250%时——可见区域还是基色循环重置时画面上都是“纯基色”——无缝衔接这是“无缝循环”的通用心法——让循环的首尾两端视觉上完全一致。技法2stroke-dashoffset是「笔尖进度条」手写签名的核心是把“画出来的线”变成“一段进度”。怎么理解把SVG路径想象成一条“虚线”.stroke{stroke-dasharray:900;stroke-dashoffset:900;}stroke-dasharray: 900—— 意思是“这条线由900px实线 900px空白交替组成”。因为路径总长度就是900左右——所以实际上整条路径就是一段900px的实线。stroke-dashoffset: 900—— 意思是“虚线整体向后偏移900px”。结果偏移900px之后原来那条 900px 的实线完全移出了可见范围——路径上什么都不显示。动画把offset从900推到0keyframesdraw1{0%{stroke-dashoffset:900;}/* 完全隐藏 */30%{stroke-dashoffset:0;}/* 完全画出 */72%{stroke-dashoffset:0;}/* 停笔 */100%{stroke-dashoffset:-900;}/* 反向擦掉 */}逐段读分段offset视觉0% → 30%900 → 0线条被“画”出来——笔尖从左往右走30% → 72%0 → 0停笔——签名完整显示72% → 100%0 → -900线条被“擦”掉——从起笔端反向消失关键offset推到负值-900——线条从起笔端开始“反向消失”。为什么是“反向”因为offset是沿路径方向的偏移正向偏移正值实线段向后推——末端的线先消失负向偏移负值实线段向前拉——起笔端的线先消失“起笔端先消失”看起来就像被“橡皮擦擦掉”——从线的起点开始一路往回擦。“写、停、擦”三幕剧一个属性全包。这是stroke-dashoffset的通用价值——所有“沿线描边”的效果进度条、路径动画、勾选对号、曲线绘制都靠它。技法3双路径 双笔顺“签名”看起来是“一笔写成”但代码里其实是“两条独立路径”。svgviewBox0 0 420 140pathclassstroke s1dM20 96 C 60 20, .../!-- 主体花体字 --pathclassstroke s2dM26 116 C 120 130, .../!-- 下划线 --/svg两条路径各自持有动画/* 主体0% ~ 30%写完72% ~ 100%擦掉 */keyframesdraw1{0%{stroke-dashoffset:900;}30%{stroke-dashoffset:0;}72%{stroke-dashoffset:0;}100%{stroke-dashoffset:-900;}}/* 下划线16%才起笔42%写完74%起擦 */keyframesdraw2{0%, 16%{stroke-dashoffset:420;}/* 前16%保持隐藏 */42%{stroke-dashoffset:0;}/* 42%写完 */74%{stroke-dashoffset:0;}/* 停笔到74% */100%{stroke-dashoffset:-420;}/* 擦掉 */}时间轴对齐0s 1.95s 3.0s 4.7s 6.5s │ │ │ │ │ ├──主体写下─┤ │ │ │ ├──主体停笔──┤ │ │ ├─下划线写下─┤ │ │ │ ├──下划线停笔┤ │ ├──一起擦──┤“笔顺感”的三个要点① 下划线的起笔比主体晚 16%——主体写了一小半下划线才“跟上”。为什么不是“等主体写完再画下划线”因为真实签名里人是“边写边补充”的——主体签名写到一半手就已经顺势拉出一道下划线。“错峰”比“严格先后”更自然。② 两条线的“擦除”基本同步——主体72%起擦下划线74%起擦——差2%。为什么不是“主体擦完再擦下划线”因为**“擦掉一个签名”是一个整体动作**——不是“先擦主字再擦下划线”而是整块内容一起被“抹掉”。③stroke-linecap: round让起笔收笔圆润.stroke{stroke-linecap:round;stroke-linejoin:round;}这是“手写质感”的最低成本——stroke-linecap: round线条的“两端”是圆头不是平头stroke-linejoin: round线条的“转折处”是圆角不是尖角少了这两行——签名的笔画会显得“生硬、像打印的”。加上这两行——笔画立刻有“手写”的温度。四、踩坑位我全踩过你直接避① 漏掉-webkit-background-clip: text/* ❌ Safari 不认光带扫不出来 */background-clip:text;/* ✅ 两行都写 */-webkit-background-clip:text;background-clip:text;Safari只认带-webkit-前缀的版本——这是Safari的历史遗留。同时还要配-webkit-text-fill-color: transparent/* ❌ 只写color: transparentSafari里会“露底” */color:transparent;/* ✅ 两行都写 */color:transparent;-webkit-text-fill-color:transparent;只写color: transparent在部分浏览器会显示出默认的黑色文字——光带效果看不到。②background-size不放大/* ❌ 渐变默认铺满100%光带“扫”不动 */background:linear-gradient(110deg,...);animation:sheen 4.2s linear infinite;keyframessheen{from{background-position:250% 0;}to{background-position:-250% 0;}}/* ✅ 先放大到250%position才有可动空间 */background-size:250% 100%;background-position是“在背景图内部移动”——如果背景图正好铺满元素position怎么动画面上都不会变化。先放大background-size——让背景图大于元素——光带才有“藏起来的空间”——position才有“可动区间”。这条规律通用——所有“扫光 / 滑动 / 移动”的background-position动画都要先把background-size放大。③dasharray给小了/* ❌ 路径真实长度超过dasharray写完一半就断 */.stroke{stroke-dasharray:400;}/* 实际路径长度900 *//* ✅ 给个足够大的数字宁可浪费不可截断 */.stroke{stroke-dasharray:900;}/* 或1200都行 */stroke-dasharray必须 ≥ 路径的实际长度。给小了——整条线被切成“实线 空白 实线 空白”——动画只能画出一部分。如何量路径的真实长度浏览器控制台一行document.querySelector(.s1).getTotalLength();返回一个数字——比如874.23——取整往上加一点900——安全值。拿不准就给天文数字——900/1200/2000——宁可浪费不可截断。④ SVGpath忘写fill: none/* ❌ 曲线内部被默认黑色填充实心块签名变墨渍 */.stroke{/* 没有fill */}/* ✅ 明确fill: none */.stroke{fill:none;}SVGpath默认fill是黑色——如果不显式设为none路径围出来的所有区域都会被填成黑色。结果你想要的“一条线”变成了“一块黑的墨渍”。这是第一次写SVG路径最容易踩的坑——fill: none是必写项。⑤ 擦除阶段没设计/* ❌ 只有“写”没有“擦”循环时笔画闪断 */keyframesdraw1{0%{stroke-dashoffset:900;}100%{stroke-dashoffset:0;}}/* 循环重置时笔画从0瞬间跳回900 —— 闪一下 *//* ✅ 让 offset 冲过 0 到负值笔画反向消失 */keyframesdraw1{0%{stroke-dashoffset:900;}30%{stroke-dashoffset:0;}/* 写完 */72%{stroke-dashoffset:0;}/* 停笔 */100%{stroke-dashoffset:-900;}/* 反向擦掉 */}只写“0 → 写完”的动画——循环重置时笔画从“写完”瞬间跳回“隐藏”——观感上就是闪一下。加上“擦除段”——offset从0推到-900——笔画从起笔端反向消失——循环天衣无缝。这是“无缝循环”的又一条通用心法——让“结束状态”和“起始状态”视觉上一致。流光首尾都是基色签名首尾都是“隐藏”五、变式挑战10–30分钟动手才有收获任务签你自己的名字。有两条路线路线A手动画路径推荐打开任意矢量软件Figma / Illustrator / Inkscape用铅笔工具Pencil随手涂一笔——像签名一样导出为SVG——拿到path的d属性替换到.s1的d...里路线B找现成的字更工程化在网上搜任意手写风格字母的SVG path很多免费字体站提供SVG复制d属性替换进.s1dasharray改成新路径的长度——浏览器控制台document.querySelector(.s1).getTotalLength()一行就能量出来调整动画时长——路径长的动画时长要长一点否则笔走太快进阶方向有余力再玩① 让签名的笔画有“粗细变化”.s1{stroke-width:3.5;}.s1:hover{stroke-width:5;}/* hover时变粗 */真实签名里笔画的粗细是变化的——CSS做不到“沿路径变化线宽”但可以用两层路径叠出效果外层细、内层粗用stroke-dashoffset错开——高级玩法。② 加“落笔的墨点”.sig::before{content:;position:absolute;...;/* 一个圆点 */animation:drop 6.5s ease-in-out infinite;}keyframesdrop{0%{opacity:0;}5%{opacity:1;}/* 起笔时墨点出现 */10%{opacity:0;}/* 墨水渗开消失 */}“落笔的墨点”是手写感的加分项——签名开始的瞬间一个小墨点出现又消失。③ 换成中文名签名中文名的难度在于笔画多——但stroke-dashoffset的原理完全一样。关键是把“多笔画”拆成多条path各自按笔顺错峰动画。这是最有意思的挑战——你可以在评论区贴出你的中文名签名我会挑几个做特写拆解。④ 让流光文字“循环更慢一点”现在4.2s一次扫过——可以试试8s或10s——“优雅”和“频率”成反比。⑤ 让流光和签名“错峰”现在两个动画独立跑流光4.2s、签名6.5s——可以让它们“同步”——比如签名写完的瞬间流光正好扫过——“笔落墨干纸面反光”。六、小结今天这一篇里藏着5个通用技能点技能适用场景background-clip: text 透明文字所有“渐变文字 / 金属字 / 流光字”background-size放大 position滑动所有“扫光 / 高光扫过”效果stroke-dashoffset做“描边进度”所有“沿线书写 / 进度条 / 对勾动画”stroke-linecap: round手写质感所有“手绘 / 手写 / 曲线”效果首尾状态一致做无缝循环所有循环动画的“重置隐蔽化”最值得记住的三条① 文字流光和手写签名本质是同一件事。“让一段渐变 / 线条按进度展示。”流光渐变 background-position动签名SVG线 stroke-dashoffset动**一个“填充”的进度一个“描边”的进度。**理解了这个统一视角你就能把两个效果都拆到最简单。②background-size不放大background-position就动不了。这是“扫光”效果的唯一前提——背景图 元素大小position怎么动画面不变背景图 元素大小position动起来光带才“扫过”“先放大再滑动”——所有扫光效果的通用公式。③ 无缝循环的关键是“结束状态 起始状态”。流光首尾都是基色光带藏在外面签名首尾都是隐藏offset冲过0到负值“让重置发生在看不见的时候”。如果这一篇对你有帮助三连支持一下这个专栏 点赞 更新加速收藏 随时复制代码评论 你想看什么效果我排进日程。本专栏所有demo复制即用随便商用。目标更新不断更。