如何实现一个SVG向另一个SVG的变形过渡动画
SVG两个状态间点击变形实现方案
前提条件
两个SVG需要满足:
- viewBox尺寸完全一致,避免变形过程中出现偏移
- 如果使用纯CSS实现,需要两个SVG内部对应路径的节点数量完全相同,你可以在Adobe Illustrator、Figma等设计工具中调整路径节点数后重新导出
方案1:纯CSS实现(无第三方依赖)
把两个SVG的路径数据整合到同一个SVG标签内,通过CSS过渡实现变形,示例代码如下:
<!-- 整合后的SVG --> <svg viewBox="0 0 200 200" width="200" height="200"> <path id="morphTarget" d="这里替换为initial.svg里对应路径的d属性值" fill="#333" /> </svg> <button id="triggerBtn">触发变形</button> <style> #morphTarget { /* 配置d属性过渡,缓入效果 */ transition: d 1s ease-in, fill 1s ease-in; } /* 变形后的状态 */ #morphTarget.active { d: path("这里替换为final.svg里对应路径的d属性值"); fill: #f00; /* 如果有颜色变化也可以一起过渡 */ } </style> <script> const btn = document.querySelector('#triggerBtn') const target = document.querySelector('#morphTarget') btn.addEventListener('click', () => { target.classList.toggle('active') }) </script>
如果是多路径的SVG,给每个对应路径分别配置过渡规则即可。
方案2:开源库实现(适配节点数不一致场景)
如果两个SVG路径节点数无法调整到一致,可以用专门做SVG变形的库实现,不需要手动对齐节点,示例逻辑如下:
// 引入库后获取两个路径的d值 const initialPath = "initial.svg的路径d值" const finalPath = "final.svg的路径d值" // 生成插值函数 const interpolate = flubber.interpolate(initialPath, finalPath, { ease: (t) => t * t // 实现ease-in缓动效果 }) const target = document.querySelector('#morphTarget') const btn = document.querySelector('#triggerBtn') btn.addEventListener('click', () => { let start = null const duration = 1000 // 动画时长1秒 function animate(timestamp) { if (!start) start = timestamp const progress = Math.min((timestamp - start) / duration, 1) target.setAttribute('d', interpolate(progress)) if (progress < 1) { requestAnimationFrame(animate) } } requestAnimationFrame(animate) })
注意事项
- 从XD导出SVG时建议取消“优化文件大小”相关的勾选,避免导出的路径被自动合并、简化导致节点不匹配
- 如果是多元素组合的SVG变形,需要把两个SVG的元素一一对应,每个元素单独做变形过渡
内容的提问来源于stack exchange,提问作者user8361147
相关产品推荐
相关产品推荐

