1. 为什么SVG文字特效值得前端花时间琢磨做前端这些年我经手过不少视觉需求从简单的渐变文字到复杂的动态标题绕来绕去发现一个规律凡是跟文字特效沾边的活儿用CSS硬扛往往能出效果但一旦遇到描边、路径动画、文字沿曲线排列这类需求CSS就开始力不从心了。这时候SVG才是真正的主角。SVG绘制文字特效说白了就是用text标签配合defs、path、mask、filter这些元素把文字当成矢量图形来处理。它跟普通HTML文字最大的区别在于HTML文字是排版引擎渲染的你能控制字号、颜色、字重但控制不了文字的形状而SVG文字本质上是图形你可以给它加描边动画、填充图案、做路径裁剪、甚至让文字沿着任意曲线跑。这套方案适合谁我总结下来有三类人最该掌握一是做营销落地页的前端经常需要那种一眼抓住人的标题动效二是做数据可视化的开发者图表里的标签文字需要特殊处理三是想提升视觉表现力的全栈工程师不想每次都求设计师切图。掌握SVG文字特效之后很多以前必须用图片或Canvas才能实现的效果现在几行代码就能搞定而且清晰度无损、可交互、可访问。这篇文章我会从最基础的SVG文字结构讲起逐步深入到描边动画、渐变填充、路径文字、遮罩特效这几个实战方向每个方向都配上可直接复制的代码和我在实际项目中踩过的坑。不堆砌API文档只讲真正用得上的东西。2. SVG文字的基础骨架与坐标系陷阱2.1 一个最小可用的SVG文字结构先看最朴素的写法这是所有特效的起点svg viewBox0 0 600 200 xmlnshttp://www.w3.org/2000/svg text x300 y120 text-anchormiddle font-size72 font-familysans-serif fill#333 文字特效 /text /svg这段代码里几个属性必须搞清楚不然特效做出来位置全是歪的viewBox定义了SVG的内部坐标系四个值分别是min-x min-y width height。它决定了你后续所有坐标的参照系。x和y是文字基线的起点位置注意y指的是基线不是文字顶部也不是底部。这一点跟CSS的top完全不同我第一次用的时候文字总是偏上就是因为把y当成了顶部。text-anchor控制水平对齐middle表示以x为中心start是左对齐end是右对齐。做居中标题必用middle。dominant-baseline控制垂直对齐可选middle、central、hanging等。想让文字在某个矩形里垂直居中用dominant-baselinemiddle配合y设为矩形中心高度。提示font-size在SVG里默认单位是用户坐标单位不是px。如果你用viewBox做了缩放实际渲染出来的字号会跟着缩放。这一点在响应式场景下要特别注意。2.2 坐标系缩放带来的字号困惑我见过太多人在这里翻车。假设你写了一个viewBox0 0 100 100的SVG然后设置font-size20在1000px宽的容器里显示实际字号会被放大10倍变成200px。这不是bug是SVG的缩放机制。解决办法有两个一是让viewBox的尺寸尽量接近实际显示尺寸比如容器宽600px就设viewBox0 0 600 xxx二是用preserveAspectRatio控制缩放行为。我个人的习惯是前者因为坐标算起来直观不用在脑子里做换算。另外text元素里的文字不会自动换行这是跟HTML文字最大的体验差异。长文本要么手动拆成多个tspan要么用foreignObject嵌入HTML。做标题特效一般文字都短这个问题不突出但做段落文字时一定要提前规划。2.3 字体加载与跨平台一致性SVG文字用的字体跟页面其他文字一样受系统字体影响。如果你用了自定义字体必须确保字体在SVG渲染前已经加载完成否则会出现字体闪烁FOUT。我的做法是在CSS里用font-display: block配合document.fonts.ready等字体就绪后再触发SVG动画。还有一个坑不同系统对同一字体的渲染宽度不一样。比如你按某个字体的宽度算好了文字居中位置换台电脑字体回退到系统默认文字宽度变了居中就偏了。解决办法是用textLength属性强制指定文字总宽度或者用getComputedTextLength()在运行时动态计算。做精确对齐的特效时我强烈建议用后者。3. 描边动画让文字像被一笔一画写出来3.1 stroke-dasharray与stroke-dashoffset的原理描边动画是SVG文字特效里最经典的一种效果就是文字像被一支笔慢慢写出来。核心靠两个属性stroke-dasharray和stroke-dashoffset。stroke-dasharray定义虚线的实线段长度和空白段长度。当你把实线段长度设成大于等于路径总长度空白段设成同样大整条路径就变成了一段实线加一段空白。然后通过stroke-dashoffset控制这段实线的偏移量就能实现逐渐画出的效果。关键问题是文字的总路径长度怎么算text元素不像path那样有明确的长度但可以用JS获取const textEl document.querySelector(#myText); const length textEl.getComputedTextLength(); textEl.style.strokeDasharray length; textEl.style.strokeDashoffset length; // 然后通过动画把 strokeDashoffset 从 length 变到 0这里有个细节getComputedTextLength()返回的是文字排版长度但描边动画实际走的是每个字形的轮廓路径两者不完全相等。实测下来把strokeDasharray设成length * 1.2左右比较保险能保证文字完全被覆盖。3.2 用CSS animation驱动描边拿到长度之后动画部分用CSS就能搞定不需要JS逐帧控制keyframes draw { to { stroke-dashoffset: 0; } } .draw-text { fill: transparent; stroke: #e63946; stroke-width: 2; animation: draw 3s ease forwards; }配合前面的JS设置初始strokeDashoffset文字就会从无到有被写出来。fill: transparent让填充先隐藏只显示描边等描边画完再考虑是否显示填充。我实际用的时候发现ease缓动会让开头快结尾慢写出来的感觉不太自然。改成linear或者自定义cubic-bezier(0.4, 0, 0.2, 1)更接近真实书写节奏。另外stroke-linecap: round和stroke-linejoin: round能让笔画端点圆润看起来更像手写。3.3 多字依次描边的编排技巧单个文字描边好看但多个字一起描边就少了层次感。想要一个字一个字写出来的效果需要给每个字单独设置动画延迟。做法是把每个字拆成独立的tspan或text然后给它们设置递增的animation-delaysvg viewBox0 0 600 200 text x50 y120 font-size80 classdraw-text styleanimation-delay: 0s文/text text x150 y120 font-size80 classdraw-text styleanimation-delay: 0.5s字/text text x250 y120 font-size80 classdraw-text styleanimation-delay: 1s特/text text x350 y120 font-size80 classdraw-text styleanimation-delay: 1.5s效/text /svg每个字的strokeDasharray和strokeDashoffset需要单独用JS计算因为每个字的长度不同。我写了个小函数批量处理document.querySelectorAll(.draw-text).forEach(el { const len el.getComputedTextLength() * 1.2; el.style.strokeDasharray len; el.style.strokeDashoffset len; });注意animation-delay是加在CSS动画上的但strokeDashoffset的初始值是JS设的。如果JS执行晚于CSS动画开始会出现闪烁。稳妥做法是给元素先加一个visibility: hiddenJS设置完再显示。3.4 描边动画的性能与兼容性实测描边动画本质上是改变stroke-dashoffset这个属性属于合成层之外的属性会触发重绘。文字少的时候无所谓但如果页面上有几十个描边文字同时动画低端设备上会掉帧。优化思路有两个一是用will-change: stroke-dashoffset提前告知浏览器但别滥用用多了反而占内存二是控制同时动画的元素数量用IntersectionObserver让文字进入视口才开始动画。兼容性方面stroke-dasharray和stroke-dashoffset在所有现代浏览器都支持包括移动端。唯一要注意的是IE不过现在基本可以不管了。Safari上有个老问题getComputedTextLength()在字体未加载完成时返回的值偏小导致描边动画提前结束。解决办法就是前面说的等document.fonts.ready之后再计算。4. 渐变与图案填充给文字穿上质感外衣4.1 linearGradient实现金属质感纯色文字太单调渐变填充是提升质感最快的方式。SVG里用linearGradient定义渐变然后通过fillurl(#gradientId)引用svg viewBox0 0 600 200 defs linearGradient idmetal x10% y10% x20% y2100% stop offset0% stop-color#f0f0f0/ stop offset30% stop-color#c0c0c0/ stop offset50% stop-color#ffffff/ stop offset70% stop-color#a0a0a0/ stop offset100% stop-color#808080/ /linearGradient /defs text x300 y130 text-anchormiddle font-size90 font-weightbold fillurl(#metal) 金属质感 /text /svg这个渐变的关键在于多个stop的明暗交替。金属反光的特征是亮-暗-亮-暗的条纹感所以我在30%和70%位置放了暗色50%位置放最亮的白色模拟高光。x1/y1/x2/y2控制渐变方向垂直渐变x相同y从0到100%最适合做金属拉丝效果。实测下来font-weight: bold对金属质感帮助很大细字体做不出厚重感。另外可以叠加一个filter做轻微模糊让高光过渡更柔和但模糊会牺牲清晰度看具体场景取舍。4.2 radialGradient做发光文字径向渐变适合做发光效果光从文字中心向外扩散defs radialGradient idglow cx50% cy50% r50% stop offset0% stop-color#fff9c4/ stop offset40% stop-color#ffeb3b/ stop offset100% stop-color#f57f17/ /radialGradient /defscx和cy是渐变中心r是半径。做发光文字时中心用接近白色的亮色边缘用饱和的暖色视觉上就像文字在发光。如果想要更强的发光感可以叠加filter里的feGaussianBlurfilter idblur feGaussianBlur stdDeviation3/ /filter然后复制一层文字底层加模糊滤镜做光晕顶层保持清晰。这种双层文字的技法在霓虹灯效果里特别常用。4.3 pattern填充做纹理文字pattern可以定义重复图案用来给文字填充纹理比如条纹、波点、格子defs pattern idstripes width10 height10 patternUnitsuserSpaceOnUse patternTransformrotate(45) rect width5 height10 fill#333/ rect x5 width5 height10 fill#f0f0f0/ /pattern /defs text fillurl(#stripes) ...条纹文字/textpatternUnitsuserSpaceOnUse表示图案坐标用SVG用户坐标这样图案不会随文字缩放而变形。patternTransform可以旋转、缩放图案做斜条纹就靠它。这里有个容易忽略的点图案的width和height决定了重复周期太小会显得密集太大又看不出纹理。我一般从10到20之间试配合patternTransform微调角度。另外图案填充的文字在小字号下会糊成一片建议字号至少48以上再用。4.4 渐变与描边的组合玩法单独用渐变或描边都不够惊艳组合起来才有层次。常见做法是填充用渐变描边用对比色再加一层阴影text x300 y130 text-anchormiddle font-size90 font-weightbold fillurl(#metal) stroke#333 stroke-width2 paint-orderstroke fill 组合特效 /textpaint-orderstroke fill这个属性很关键它让描边画在填充下面这样描边不会盖住填充的渐变细节文字看起来更立体。默认顺序是fill stroke markers描边会压在填充上视觉上文字会变瘦。我做过一个对比测试同样的渐变文字加paint-order调整前后前者明显更饱满。这个属性在现代浏览器支持良好可以放心用。5. 路径文字让文字沿着任意曲线跑5.1 textPath的基本用法让文字沿着曲线排列靠的是textPath元素配合pathsvg viewBox0 0 600 300 defs path idcurve dM 50 200 Q 300 50 550 200 fillnone/ /defs text font-size32 fill#333 textPath href#curve startOffset50% text-anchormiddle 文字沿着这条曲线排列 /textPath /text /svgpath的d属性定义曲线M是起点Q是二次贝塞尔曲线一个控制点C是三次贝塞尔两个控制点。textPath的href指向路径的idstartOffset控制文字在路径上的起始位置50%表示从中间开始。text-anchormiddle配合startOffset50%能让文字在曲线上居中这个组合做弧形标题特别实用。5.2 路径方向与文字可读性路径文字有个反直觉的地方文字是沿着路径的方向排列的。如果路径是从右往左画的文字就会倒过来。所以画路径时要注意方向从左到右、从上到下是正常阅读方向。另外曲线弯曲程度太大时文字会挤在一起或者拉得很开。这是因为textPath按路径长度均匀分布文字曲率大的地方单位长度对应的视觉宽度小。解决办法是调整路径的曲率或者用letter-spacing微调字间距。我一般会把曲线的控制点拉远一点让曲率平缓些。5.3 动态路径文字的实现思路静态路径文字好看但动态的更有冲击力。常见需求是文字沿着路径流动或者逐个出现。流动效果靠动画startOffsetkeyframes flow { from { start-offset: 0%; } to { start-offset: 100%; } }不过start-offset在CSS里不是标准属性需要用JS或者SMIL动画。SMIL写法textPath href#curve 流动的文字 animate attributeNamestartOffset from0% to100% dur5s repeatCountindefinite/ /textPathSMIL动画在Chrome和Firefox支持良好Safari也支持但部分场景下性能不如CSS。如果追求性能可以用JS的requestAnimationFrame手动更新startOffset。逐个出现的效果则是把文字拆成多个tspan每个tspan设置不同的opacity动画延迟。这个跟前面描边动画的编排思路一样。5.4 路径文字的实战避坑我在项目里用路径文字踩过几个坑这里集中说一下。第一个坑路径不可见但必须存在。path如果设了fillnone和strokenone有些浏览器会认为路径无效导致文字不显示。稳妥做法是设stroketransparent或者stroke-width0保留路径的存在感。第二个坑viewBox和路径坐标不匹配。路径的坐标是相对于SVG用户坐标系的如果viewBox设得不对路径可能跑到可视区域外文字自然就看不见了。调试时先把路径的stroke设成可见颜色确认路径位置对了再隐藏。第三个坑文字太长超出路径。textPath不会自动截断超出路径长度的文字会消失。可以用textLength限制总长度或者提前用getComputedTextLength()判断。6. 遮罩与裁剪文字特效的高级玩法6.1 mask实现文字渐隐渐现mask可以控制元素的可见区域用它做文字渐隐效果非常自然defs mask idfadeMask rect width600 height200 fillurl(#fadeGradient)/ /mask linearGradient idfadeGradient stop offset0% stop-color#000/ stop offset50% stop-color#fff/ stop offset100% stop-color#000/ /linearGradient /defs text maskurl(#fadeMask) ...渐隐文字/text遮罩的原理是白色区域完全显示黑色区域完全隐藏灰色区域半透明。所以渐变从黑到白再到黑文字就呈现两端淡出、中间清晰的效果。这个技法做文字从雾中浮现的动画特别好用。把渐变的offset做成动画文字就会逐渐显现。6.2 clipPath做文字裁剪clipPath跟mask类似但只有显示和隐藏两种状态没有半透明。用它可以把文字裁剪成特定形状defs clipPath idcircleClip circle cx300 cy100 r80/ /clipPath /defs text clip-pathurl(#circleClip) ...被圆形裁剪的文字/text文字超出圆形区域的部分会被裁掉只保留圆内的部分。这个技法做文字从圆形里透出来的效果很直接。clipPath和mask的区别在于性能和精度clipPath性能更好但边缘是硬切的mask支持渐变和半透明但性能开销大一些。做硬边裁剪用clipPath做柔和过渡用mask。6.3 文字作为遮罩裁剪图片反过来也可以用文字作为遮罩去裁剪图片实现图片填充文字的效果defs mask idtextMask text x300 y130 text-anchormiddle font-size100 font-weightbold fill#fff图片文字/text /mask /defs image hrefyour-image.jpg width600 height200 maskurl(#textMask)/文字在遮罩里是白色所以图片只在文字形状的区域显示视觉上就是图片填充在文字里。这个效果做视频封面、海报标题特别出彩。注意image的href在旧版浏览器里要用xlink:href现在现代浏览器都支持href了但为了兼容性可以两个都写。6.4 遮罩动画的性能考量遮罩动画虽然好看但性能是它的软肋。每次遮罩变化都会触发整个被遮罩元素的重新合成元素大、动画复杂时容易掉帧。优化建议一是尽量用clipPath代替mask如果不需要半透明效果二是把遮罩动画限制在小区域别让整个页面都参与重绘三是用transform动画代替遮罩属性动画因为transform走合成层性能好得多。我做过一个测试同样大小的文字用mask做渐隐动画在低端安卓机上帧率只有30左右改成用opacity配合transform模拟类似效果帧率能稳定在55以上。所以能用简单属性实现的效果就别上遮罩。7. 实战组合一个完整的SVG文字特效案例7.1 需求拆解与技术选型假设要做一个营销页面的主标题特效需求是文字有金属渐变填充入场时逐个描边写出写完后有轻微发光呼吸效果整体沿一条平缓的弧线排列。拆解一下金属渐变用linearGradient逐个描边用多text加animation-delay发光呼吸用filter的feGaussianBlur配合opacity动画弧线排列用textPath。但这里有个冲突textPath要求文字在一个text里而逐个描边要求文字拆成多个text。两者不能直接共存。我的解决方案是放弃textPath用多个text手动计算每个字的坐标模拟弧线排列。虽然麻烦点但可控性更强。7.2 逐字坐标计算与动画编排弧线排列的坐标计算用圆的参数方程假设弧线是半径为R的圆的一部分圆心在(cx, cy)每个字的角度是θ那么字的坐标是x cx R * cos(θ) y cy R * sin(θ)用JS批量计算const chars [文, 字, 特, 效, 演, 示]; const cx 300, cy 400, R 300; const startAngle -Math.PI * 0.7; const angleStep Math.PI * 0.4 / (chars.length - 1); chars.forEach((char, i) { const angle startAngle angleStep * i; const x cx R * Math.cos(angle); const y cy R * Math.sin(angle); // 创建 text 元素设置 x, y, 旋转角度 // 旋转角度 angle Math.PI / 2让文字垂直于弧线 });每个字的旋转角度要加上90度Math.PI / 2这样文字才是站在弧线上的而不是平躺。动画编排上每个字的描边动画延迟设为i * 0.3s发光呼吸动画在所有描边完成后开始用animation-delay叠加。7.3 完整代码与效果调优把上面的思路整合成完整代码核心结构如下svg viewBox0 0 600 500 xmlnshttp://www.w3.org/2000/svg defs linearGradient idmetal x10% y10% x20% y2100% stop offset0% stop-color#f5f5f5/ stop offset35% stop-color#b0b0b0/ stop offset50% stop-color#ffffff/ stop offset65% stop-color#909090/ stop offset100% stop-color#606060/ /linearGradient filter idglow feGaussianBlur stdDeviation4 resultblur/ feMerge feMergeNode inblur/ feMergeNode inSourceGraphic/ /feMerge /filter /defs g idtextGroup/g /svgJS部分负责生成文字、计算坐标、设置动画。调优时重点看三个地方描边速度是否跟文字复杂度匹配笔画多的字要慢一点、发光强度是否过曝stdDeviation别超过5、弧线曲率是否影响可读性曲率太大文字会挤。我实际调这个效果花了大概两小时大部分时间在微调每个字的延迟和发光参数。经验是动画总时长控制在3到4秒太短显得仓促太长用户等不及。发光呼吸的周期设2秒左右幅度别太大轻微即可。7.4 响应式适配与降级方案SVG的响应式靠viewBox和preserveAspectRatio。默认preserveAspectRatioxMidYMid meet会保持宽高比并居中适合大多数场景。如果想让文字铺满容器用preserveAspectRationone但文字会被拉伸变形一般不推荐。降级方案要考虑两种情况一是不支持SVG的极老浏览器基本可以忽略二是用户开启了减少动态效果prefers-reduced-motion。后者是真实存在的需求做动画时应该尊重media (prefers-reduced-motion: reduce) { .draw-text { animation: none; stroke-dashoffset: 0; fill: url(#metal); } }这样用户在系统里开了减少动效文字就直接显示最终状态不做描边动画。这是无障碍的基本要求别忽略。8. 我踩过的那些坑与性能优化心得8.1 字体加载时序导致的描边错位前面提过字体加载的问题这里展开说。getComputedTextLength()在字体未加载时返回的是回退字体的宽度等自定义字体加载完文字宽度变了但strokeDasharray还是按旧宽度设的结果就是描边动画要么提前结束要么拖尾。我的解决方案是监听document.fonts.readydocument.fonts.ready.then(() { initStrokeAnimation(); });如果字体是通过font-face加载的还可以用document.fonts.load(72px MyFont)精确等待某个字体。这个坑我在三个项目里都遇到过每次都是字体加载时序的问题现在成了条件反射写描边动画必加字体等待。8.2 大量SVG元素的渲染开销一个页面上如果有几十个SVG文字特效每个都带滤镜和动画性能会急剧下降。我做过压力测试50个带feGaussianBlur的文字同时动画中端笔记本上帧率掉到20以下。优化手段有几个一是用use复用定义好的图形减少DOM节点二是把不动的文字合并成一个text减少元素数量三是用IntersectionObserver做懒动画只让视口内的文字动四是滤镜尽量用CSS的filter代替SVG的feGaussianBlur前者在某些浏览器上有硬件加速。实测下来IntersectionObserver加懒动画的效果最明显能把初始渲染时间减少60%以上。8.3 移动端的触摸与缩放问题SVG在移动端有个默认行为双指缩放会缩放整个页面而不是SVG。如果想让SVG独立缩放需要设置touch-actionsvg { touch-action: none; }但这会禁用页面的滚动要谨慎使用。大多数文字特效不需要交互保持默认即可。另一个移动端问题是viewBox在小屏幕上的表现。如果viewBox设得太大文字在小屏上会缩得很小看不清。我的做法是用媒体查询针对小屏调整viewBox或者用JS动态计算合适的viewBox。8.4 可访问性与SEO的兼顾SVG文字对屏幕阅读器是可见的但如果你把文字拆成多个text做动画阅读器会逐个读出来体验很差。解决办法是给SVG加roleimg和aria-label把完整文字放在aria-label里然后给内部的text加aria-hiddentruesvg roleimg aria-label文字特效演示 text aria-hiddentrue文/text text aria-hiddentrue字/text ... /svgSEO方面SVG文字是能被搜索引擎抓取的但权重不如HTML文字。如果这段文字对SEO重要建议在SVG旁边放一个视觉隐藏的HTML版本h1 classsr-only文字特效演示/h1.sr-only是常见的视觉隐藏类不影响布局但能被搜索引擎和屏幕阅读器读取。8.5 调试SVG的实用工具与技巧调试SVG比调试HTML麻烦因为元素不可见时很难定位。我的几个常用技巧一是临时给所有path和text加strokered stroke-width1看清它们的实际位置和形状。二是用浏览器的开发者工具选中SVG元素Chrome和Firefox都能高亮显示元素的边界框。三是用rect画参考线确认坐标系对齐。还有一个神器是SVG的view元素配合preserveAspectRatio可以快速切换不同的视图区域调试大尺寸SVG时特别方便。不过这个用得少知道有这回事就行。9. 从特效到产品什么场景该用SVG文字9.1 适合与不适合的场景对比SVG文字特效虽好但不是万能。我整理了一个对比表帮你快速判断场景推荐方案理由营销页主标题动效SVG文字视觉冲击强清晰度无损数据图表标签SVG文字与图表坐标系天然契合正文段落文字HTML文字SVG不支持自动换行排版麻烦大量文字列表HTML文字SVG元素多性能差需要文本选择的场景HTML文字SVG文字选择体验差文字沿曲线排列SVG文字CSS无法实现文字填充图片/视频SVG文字mask/clipPath是唯一方案核心判断标准如果文字需要被当成图形处理用SVG如果文字就是用来读的用HTML。9.2 与Canvas方案的取舍Canvas也能画文字特效而且性能通常更好。两者的区别在于SVG是声明式的DOM结构清晰可交互、可访问、可被CSS控制Canvas是命令式的一切靠JS绘制灵活但维护成本高。我的选择标准是需要交互hover、click和可访问性的用SVG纯展示、元素数量极大上千个的用Canvas。文字特效一般元素不多SVG是更合适的选择。9.3 一个真实项目的技术决策复盘之前做过一个活动页面主标题需要文字从火焰中浮现的效果。最初方案是用Canvas逐帧绘制火焰粒子加文字遮罩效果很炫但代码量巨大而且移动端性能堪忧。后来改成SVG方案用feTurbulence滤镜生成火焰纹理配合feDisplacementMap做扭曲文字用mask控制浮现。代码量减少了70%性能反而更好因为SVG的滤镜是浏览器原生实现的比JS逐帧绘制高效得多。这个经历让我意识到SVG的滤镜系统被严重低估了。feTurbulence、feDisplacementMap、feColorMatrix这些滤镜组合起来能做出很多看起来需要WebGL才能实现的效果。值得花时间研究。9.4 后续可以深入的方向如果你已经把基础的文字特效玩熟了接下来可以往这几个方向深入一是SVG滤镜的进阶组合做火焰、水波、玻璃质感二是SVG与Web Animations API结合用JS精确控制动画时间线三是SVG文字与Three.js结合把SVG作为纹理贴到3D物体上四是研究foreignObject嵌入HTML做复杂排版。我个人最近在琢磨的是SVG文字的路径变形动画就是让文字的形状本身发生渐变从一个字变成另一个字。这需要用到path的d属性插值目前还没有特别成熟的方案但已经有一些实验性的库在做这件事。等有稳定方案了再单独写一篇分享。最后说个实在的SVG文字特效的学习曲线不算陡但细节特别多每个属性都有坑。我的建议是别一次学太多挑一个效果比如描边动画吃透把相关的属性、兼容性、性能问题都摸清楚再学下一个。贪多嚼不烂这是我做了这么多年前端最深的体会。