最近在工作中新接触到一个词叫svg,最开始呢以为单纯的是svga动效格式的简称,但是随着调查的深入,才发现这是一个世外桃源,话不多说,接下来就来看看这个新“视”界吧!
前端常用动效实现手段:
CSS3 transition、animation 针对dom元素操作
Lottie => 直播状态,json格式动画文件
Canvas动画 => 图标,部分活动画图
requestAnimationFrame(svga) => 活动banner或礼物呈现效果
javascript直接实现
SVG(可伸缩矢量图形)
gif图
简介
SVG(scalable vector graphics)指可伸缩矢量图形,是使用 XML 来描述二维图形和绘图程序的语言。用来定义用于网络的基于矢量的图形,使用xml定义图形,在图像放大或者改变尺寸的时候,图形质量不会有所损失。是万维网联盟的标准,与诸如dom和xsl之类的w3c标准的一个整体。
SVG的优势
- SVG 可被非常多的工具读取和修改(比如记事本)
- SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。
- SVG 是可伸缩的
- 可在任何的分辨率下被高质量地打印
- 图像质量不下降的情况下被放大
- 图像中的文本是可选的,同时也是可搜索的(很适合制作地图)
- 可以与java技术一起运行
- 开放的标准
- 是纯粹的xml
页面导入svg的方法
我们可以到阿里巴巴矢量图标库去下载一个svg格式的图标来尝试在页面中导入并展示出来。我就用支付类型的icon来举例:
如图,红色框框圈起来的就是可以下载后即可利用图片、iframe标签、embed标签、object标签来引入,绿色框框圈起来的即是svg标签来导入页面展示的方式。
<p>react-svg展示</p>
{/* 这种方式需要在react项目中全局下载react-svg包并引入
import { ReactSVG } from 'react-svg';*/}
<ReactSVG src='支付类型.svg' />
<p>svg标签展示</p>
<svg t="1627453785432" class="icon" viewBox="0 0 1068 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1343" width="200" height="200">
<path d="M3.71 0h1024v1024H3.71z" fill="#8A8A8A" fill-opacity="0" p-id="1344"></path>
<path d="M402.217 278.23h215.296c66.56 0 117.418-151.894 117.418-151.894 0-45.525-4.309-79.957-78.293-82.347-73.984-2.432-91.69 54.358-144.853 54.358-54.443 0-81.707-44.672-148.736-54.4-66.987-9.686-78.294 36.864-78.294 82.389 0 0 50.774 151.893 117.462 151.893z m227.03 46.975h-227.03c-251.435 0-313.174 519.382-313.174 519.382 0 68.266 52.566 136.746 117.42 136.746h618.495c64.853 0 117.419-68.522 117.419-136.746 0 0-61.739-519.382-313.13-519.382z m25.77 399.19c15.19 0 27.477 12.928 27.477 28.842 0 15.958-12.288 28.886-27.477 28.886h-111.36v75.69a29.227 29.227 0 0 1-13.398 25.771 26.283 26.283 0 0 1-27.946 0 29.227 29.227 0 0 1-13.44-25.77v-75.691H376.83c-15.19 0-27.477-12.928-27.477-28.886 0-15.914 12.288-28.842 27.477-28.842h112.043v-36.651H376.83c-15.19 0-27.477-12.928-27.477-28.843 0-15.957 12.288-28.842 27.477-28.842h75.733L375.038 485.12a29.696 29.696 0 0 1 10.667-38.23 26.667 26.667 0 0 1 36.821 9.387l93.355 173.782h4.693l93.397-173.782a26.71 26.71 0 0 1 37.462-10.538c13.141 7.978 17.621 25.6 10.026 39.381l-77.525 144.939h71.083c15.19 0 27.477 12.928 27.477 28.842 0 15.958-12.288 28.886-27.477 28.886h-111.36v36.608h111.36z" fill="#000" p-id="1345"></path>
</svg>
<p>图片导入svg</p>
<img src="支付类型.svg" alt="" />
<p>ifram导入svg</p>
<iframe src="支付类型.svg" frameborder="0" className='ifram'></iframe>
<p>object导入svg</p>
<object data="支付类型.svg" type='image/svg+xml'></object>
<p>embed导入svg</p>
<embed src="支付类型.svg" type='image/svg+xml'></embed>
语法
svg代码都放在顶层标签<svg></svg>
中,width和height属性制定了图像在html元素中所占据的宽高。除了相对单位,也可采用绝对单位(eg:像素)。如果不指定这两个属性,默认的大小是 300px * 150px 。
如果只想展示svg图像的一部分,就要指定viewBox属性。
<svg width='500' height='300' viewBox='0 0 500 300'></svg>
viewBox 视图展示的位置和宽高范围 x,y,w,h
M = moveto 相当于 canvas 里的moveTo(),用于移动起始点 x,y(M20, 30)
L = lineto 相当于 canvas 里的lineTo(),用于画线 x,y(L30, 20)
H 用于画水平线 x(H20)
V 用于画竖直线 y(V30)
C 三次贝塞尔曲线 x1,y1,x2,y2,x3,y3(C10,20,30,40,50, 60)
S 同样三次贝塞尔曲线,更平滑
Q 二次贝塞尔曲线 x1,y1,x2,y2(Q10,20,30,40)
T 同样二次贝塞尔曲线,更平滑
A = arcTo 用于画弧
Z = closepath 相当于closeTo(),关闭path
线
线段——line
<svg viewBox='0 0 90 90' width='90' height='100%' className="stick">
<line x1='45' y1='0' x2='45' y2='90' stroke='brown' strokeWidth='5'></line>
</svg>
折线——polyline
<svg viewBox='0 0 90 90' width='90' height='100%' className="stick">
<polyline points='45,0 35,50 55,50' fill='brown' strokeWidth='3px' stroke='black'></polyline>
</svg>
多边形——polygon
<svg viewBox='-5 -5 120 120' width='120' height='120' className='car'>
<polygon points='0,0 90,0 43,80 1,89' strokeWidth='3' stroke='red'></polygon>
</svg>
折线和多边形的区别在于,多边行自动封闭路径是个完整的形状。
文字——text
<svg viewBox='-5 -5 120 120' width='120' height='120' className='car'>
<text x='0' y='100' fill='none' fontSize='30px' stroke='red' strokeWidth='1px'>这是svg</text>
</svg>
注:文字颜色用fill来设置
椭圆——ellipse
<svg viewBox='0 0 120 120' width='120' height='120' className='car'>
<ellipse cx='60' cy='60' rx='20' ry='40'></ellipse>
</svg>
矩形——rect
<svg viewBox="90 -6 300 108">
<rect x='0' y='0' width="100px" height="100px" fill='rgb(0,0,255)' stroke="red" strokeWidth='4' strokeOpacity='0.5'/>
<rect className='style-rect'/>
</svg>
.style-rect{
width: 100px;
height: 100px;
fill: rgb(0,0,255);
stroke:red;
stroke-width:4;
stroke-opacity:1;
x:150;
y:0;
transition: all 2s;
}
.style-rect:hover{ // 鼠标滑过变色
fill: orange;
stroke: orange;
}
这里我们可以看到在标签上设定的属性也可以通过css来控制,并且可以通过事件来更改原有svg的样式。
而要想不通过js或css来给svg添加动画,则可以利用animateTransform标签实现。
<p>手动画风车</p>
<div className='windmill'>
<svg viewBox='0 0 90 90' width='90' height='100%' className="stick">
{/* 线段 */}
<line x1='45' y1='0' x2='45' y2='90' stroke='brown' strokeWidth='5'></line>
{/* 折线 */}
{/* <polyline points='45,0 35,50 55,50' fill='brown' strokeWidth='3px' stroke='black'></polyline> */}
</svg>
<svg viewBox='0 -45 90 90' width='90' height='90' className='car'>
{/* path画风车叶 */}
<path d='M0 0 L45 0 L0 45 L0 0 Z' fill='red'></path>
<path d='M45 0 L90 0 L90 -45 L45 0 Z' fill='blue'></path>
<path d='M45 0 L45 -45 L0 -45 L45 0 Z' fill='yellow'></path>
<path d='M45 0 L45 45 L90 45 L45 0 Z' fill='pink'></path>
{/* polyline画风车叶 */}
{/* <polyline points='45,0 45,-45 0,-45 45,0 90,-45 90,0 45,0 90,45 45,45 45,0 0,45 0,0 45,0' fill='green' ></polyline> */}
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 0 0" to="360 0 0" dur="5s" repeatCount="indefinite" transformOrigin='center'></animateTransform>
</svg>
</div>
克隆——use
<svg viewBox="90 -6 300 108">
<rect id='clone' className='style-rect'/>
<use href="#clone" x='150' y='0'></use>
</svg>
**注:**克隆后的元素不会有根元素的事件变化(style-rect上的hover事件在use出现的元素上不触发)
组件——g
<svg viewBox="90 -6 300 108">
<g id='clone'>
<rect x='0' y='0' width="100px" height="100px" fill='rgb(0,0,255)' stroke="red" strokeWidth='4' strokeOpacity='0.5'/>
<rect className='style-rect'/>
</g>
{/* 复制 */}
<use href="#clone" x='350' y='0'></use>
</svg>
声明——defs
<svg viewBox="90 -6 300 108">
{/* 声明,不展示 */}
<defs>
// 组件
<g id='clone'>
<rect x='0' y='0' width="100px" height="100px" fill='rgb(0,0,255)' stroke="red" strokeWidth='4' strokeOpacity='0.5'/>
</g>
</defs>
{/* 复制 */}
<use href="#clone" x='350' y='0'></use> */}
</svg>
平铺——pattern
pattern用于定义一个自定义形状,该形状可以被引用来平铺一个区域
<svg width='500' height='500'>
<defs>
<pattern id='dots' x='0' y='0' width='100' height='100' patternUnits='userSpaceOnUse'>
<circle fill='#bee9e8' cx='50' cy='50' r='35'></circle>
</pattern>
</defs>
<rect x='0' y='0' width='100%' height='100%' fill='url(#dots)'></rect>
</svg>
图片——image
可以但是完全没必要这样处理,而且svg可拉伸,图片拉伸容易失真
<svg viewBox='0 0 300 320' width='120' height='120'>
<image xlinkHref='支付类型.svg'></image>
</svg>
动画——animate
<svg width='1000' height='1000'>
<rect x='0' y='0' width='100' height='50' fill='orange'>
<animate attributeName='x' from='0' to='500' dur='2s' repeatCount='indefinite'></animate>
<animate attributeName='y' from='0' to='500' dur='2s' repeatCount='indefinite'></animate>
</rect>
</svg>
项目应用
最近刚好开发的项目中呢用到了svg,如图中的线路图,分别由两条线路绘制而成,一条线路就是暗色的线路背景,另一条就是亮色会根据用户完成进度而动态绘制的线路,最一开始呢,采用的是canvas的代码来写
const p1 = [0, 300] // 贝塞尔曲线所需控制点
const p2 = [60, 300]
const p3 = [180, 100]
const p4 = [300, 250]
const p5 = [400, 250]
const p6 = [560, 150]
const p7 = [760, 110]
const [scale, setScale] = useState([1, 1, 0, 0, 0, 0]) // 各阶段比例
const ctx = useRef(null)// 高亮路线
const content = useRef(null)// 暗路线
useEffect(() => { // 当数据刷新绘制路线
drawRoad()
}, [scale])
// 路线背景
function drawBg() {
content.current = $('#bg-canvas').get(0).getContext('2d')// 找到元素并获取2d画图权限
content.current.beginPath() // 开始绘图
content.current.translate(0, 0) // 设置绘图原点
content.current.moveTo(p1[0], p1[1])
content.current.bezierCurveTo(0, 300, 60, 300, p2[0], p2[1])
content.current.bezierCurveTo(120, 300, 120, 100, p3[0], p3[1])
content.current.bezierCurveTo(240, 100, 240, 250, p4[0], p4[1])
content.current.bezierCurveTo(300, 250, 400, 250, p5[0], p5[1])
content.current.bezierCurveTo(480, 250, 480, 150, p6[0], p6[1])
content.current.bezierCurveTo(710, 150, 710, 110, p7[0], p7[1])
content.current.lineWidth = 10// 设置线的宽度
content.current.strokeStyle = '#B96E73' // 设置描边样式
content.current.stroke() // 对路径描边
}
// 画线路
const drawRoad = () => {
ctx.current = $('#my-canvas').get(0).getContext('2d')// 找到元素并获取2d画图权限
ctx.current.translate(0, 0) // 设置绘图原点
drawLine(scale[0] * 100, [p1[0], p1[1], 60, 300, 60, 300, p2[0], p2[1]])
.then(() => drawLine(scale[1] * 100, [p2[0], p2[1], 120, 300, 120, 100, p3[0], p3[1]]))
.then(() => drawLine(scale[2] * 100, [p3[0], p3[1], 240, 100, 240, 250, p4[0], p4[1]]))
.then(() => drawLine(scale[3] * 100, [p4[0], p4[1], 300, 250, 400, 250, p5[0], p5[1]]))
.then(() => drawLine(scale[4] * 100, [p5[0], p5[1], 480, 250, 480, 150, p6[0], p6[1]]))
.then(() => drawLine(scale[5] * 100, [p6[0], p6[1], 710, 150, 710, 110, p7[0], p7[1]]))
}
// 画线
const drawLine = (scale, arr) => {
return new Promise((resolve) => {
let num = 0
let timer = setInterval(() => {
ctx.current.beginPath() // 开始绘图
for (let i = 1; i < num; i++) {
let x = arr[0] * (1 - 0.01 * i) * (1 - 0.01 * i) * (1 - 0.01 * i) + 3 * arr[2] * (0.01 * i) * (1 - 0.01 * i) * (1 - 0.01 * i) + 3 * arr[4] * (0.01 * i) * (0.01 * i) * (1 - 0.01 * i) + arr[6] * (0.01 * i) * (0.01 * i) * (0.01 * i)
let y = arr[1] * (1 - 0.01 * i) * (1 - 0.01 * i) * (1 - 0.01 * i) + 3 * arr[3] * (0.01 * i) * (1 - 0.01 * i) * (1 - 0.01 * i) + 3 * arr[5] * (0.01 * i) * (0.01 * i) * (1 - 0.01 * i) + arr[7] * (0.01 * i) * (0.01 * i) * (0.01 * i)
ctx.current.lineTo(x, y)
}
ctx.current.lineWidth = 10// 设置线的宽度
ctx.current.strokeStyle = '#F2645E' // 设置描边样式
ctx.current.stroke() // 对路径描边
ctx.current.closePath()
if (num === scale) {
clearInterval(timer)
resolve(true)
}
num++
}, 10)
})
}
<canvas id="my-canvas" width='750' height='430' />
<canvas id="bg-canvas" width='750' height='430' />
而用svg的代码
const getData = () => {
// 数据请求 axios.get()
setScale([1, 1, 0, 0, 0, 0])
scaleRef.current = [1, 1, 0, 0, 0, 0]
sum.current = scaleRef.current.reduce((pre, cur) => {
return pre + cur * 100
}, 0)
}
useEffect(() => { // 数据刷新绘制路线
if (sum.current !== null) {
let kfs = document.styleSheets[0] // 动态更改keyframes属性值
kfs.insertRule(`@keyframes dash {
to {
stroke-dashoffset: ${1000 - sum.current};
}
}`) }
}, [sum.current])
<svg width='375' height='215' viewBox='0 0 750 430'>
<path d='M0,300 C0,300 60,300 60,300 C120,300 120,100 180,100 C240,100 240,250 300,250 C300,250 400,250 400,250 C480,250 480,150 560,150 C710,150 710,110 760,110' stroke='#B96E73' strokeWidth='10px' fill='none'/>
<path d='M0,300 C0,300 60,300 60,300 C120,300 120,100 180,100 C240,100 240,250 300,250 C300,250 400,250 400,250 C480,250 480,150 560,150 C710,150 710,110 760,110' stroke='#F2645E' strokeWidth='10px' fill='none'className='road'/>
</svg>
// css样式
.road {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 3s linear forwards;
}
@keyframes dash {
// to {
// stroke-dashoffset: 800;
// }
}
通过以上对比,可以明显感受到svg的代码精简了很多,但我个人使用下来的感受是canvas更容易与逻辑结合去处理(动态获取值绘制),svg更适合去做非动态绘制。这个项目中我采用的就是暗线svg,亮线用canvas,二者相结合。关于为什么不用纯svg来实现,具体原因呢有以下几种:
- svg中的贝塞尔曲线无法像canvas一样通过函数计算好下一个X,Y的坐标通过lineto()属性来控制线的走向;
- 由于曲线并不规则,每段任务在线上的距离并不是精确的百分比可以控制的,所以keyframes中的属性值并不好把控;
- 用最少的代码来实现高质量的效果一直都是前端的追求,所以二者想结合来实现是最好的选择
其它相关
如果有对贝塞尔曲线感兴趣的同学可以点击查看贝塞尔曲线
补充:
最近对svg路径有了新的认知,来更新下,之前呢,定义的是贝塞尔曲线这样的特殊路径没办法通过动态数据来渲染动画,实际上是可以的,如图,我们可以通过cssstroke-dasharray
属性来将边框变成虚线
再加点动画,让他动起来
.path {
stroke-dasharray: 100;
animation: dash 5s linear;
}
@keyframes dash {
to {
stroke-dashoffset: 1000;
}
}
将stroke-dasharray
属性设置的足够长,超过整个线条的长度,就会在视觉上造成一种绘制路径的效果,
.path {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 5s linear forwards;
}
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
svg复杂动画代码展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>生日快乐</title>
</head>
<style>
@import url(https://fonts.googleapis.com/css?family=Lato:300italic);
html,
body {
width: 100%;
height: 100%;
}
body {
background: #ee9ca7;
}
#cake {
display: block;
position: relative;
margin: -10em auto 0 auto;
}
/* ============================================== Candle
*/
.velas {
background: #ffffff;
border-radius: 10px;
position: absolute;
top: 228px;
left: 50%;
margin-left: -2.4px;
margin-top: -8.33333333px;
width: 5px;
height: 35px;
transform: translateY(-300px);
backface-visibility: hidden;
animation: in 500ms 6s ease-out forwards;
}
.velas:after,
.velas:before {
background: rgba(255, 0, 0, 0.4);
content: "";
position: absolute;
width: 100%;
height: 2.22222222px;
}
.velas:after {
top: 25%;
left: 0;
}
.velas:before {
top: 45%;
left: 0;
}
/* ============================================== Fire
*/
.fuego {
border-radius: 100%;
position: absolute;
top: -20px;
left: 50%;
margin-left: -2.6px;
width: 6.66666667px;
height: 18px;
}
.fuego:nth-child(1) {
animation: fuego 2s 6.5s infinite;
}
.fuego:nth-child(2) {
animation: fuego 1.5s 6.5s infinite;
}
.fuego:nth-child(3) {
animation: fuego 1s 6.5s infinite;
}
.fuego:nth-child(4) {
animation: fuego 0.5s 6.5s infinite;
}
.fuego:nth-child(5) {
animation: fuego 0.2s 6.5s infinite;
}
/* ============================================== Animation Fire
*/
@keyframes fuego {
0%, 100% {
background: rgba(254, 248, 97, 0.5);
box-shadow: 0 0 40px 10px rgba(248, 233, 209, 0.2);
transform: translateY(0) scale(1);
}
50% {
background: rgba(255, 50, 0, 0.1);
box-shadow: 0 0 40px 20px rgba(248, 233, 209, 0.2);
transform: translateY(-20px) scale(0);
}
}
@keyframes in {
to {
transform: translateY(0);
}
}
.text {
color: #8b6a60;
font-family: 'Lato', sans-serif;
font-weight: 300;
font-style:italic;
text-align: center;
}
</style>
<body>
<div class="velas">
<div class="fuego"></div>
<div class="fuego"></div>
<div class="fuego"></div>
<div class="fuego"></div>
<div class="fuego"></div>
</div>
<svg id="cake" version="1.1" x="0px" y="0px" width="200px" height="500px" viewBox="0 0 200 500" enable-background="new 0 0 200 500" xml:space="preserve">
<path fill="#a88679" d="M173.667-13.94c-49.298,0-102.782,0-147.334,0c-3.999,0-4-16.002,0-16.002
c44.697,0,96.586,0,147.334,0C177.667-29.942,177.668-13.94,173.667-13.94z">
<animate id="bizcocho_3" attributeName="d" calcMode="spline" keySplines="0 0 1 1; 0 0 1 1" begin="relleno_2.end" dur="0.3s" fill="freeze" values="
M173.667-13.94c-49.298,0-102.782,0-147.334,0c-3.999,0-4-16.002,0-16.002
c44.697,0,96.586,0,147.334,0C177.667-29.942,177.668-13.94,173.667-13.94z
;
M173.667,411.567c-47.995,12.408-102.955,12.561-147.334,0
c-3.848-1.089-0.189-16.089,3.661-15.002c44.836,12.66,90.519,12.753,139.427,0.07
C173.293,395.631,177.541,410.566,173.667,411.567z
;
M173.667,427.569c-49.795,0-101.101,0-147.334,0c-3.999,0-4-16.002,0-16.002
c46.385,0,97.539,0,147.334,0C177.668,411.567,177.667,427.569,173.667,427.569z
" />
</path>
<path fill="#8b6a60" d="M100-178.521c1.858,0,3.364,1.506,3.364,3.363c0,0,0,33.17,0,44.227
c0,19.144,0,57.431,0,76.574c0,10.152,0,40.607,0,40.607c0,1.858-1.506,3.364-3.364,3.364l0,0c-1.858,0-3.364-1.506-3.364-3.364c0,0,0-30.455,0-40.607c0-19.144,0-57.432,0-76.575c0-11.057,0-44.226,0-44.226C96.636-177.015,98.142-178.521,100-178.521
L100-178.521z">
<animate id="relleno_2" attributeName="d" calcMode="spline" keySplines="0 0 1 1; 0 0 1 1; 0 0 0.58 1" begin="bizcocho_2.end" dur="0.5s" fill="freeze" values="
M100-178.521c1.858,0,3.364,1.506,3.364,3.363c0,0,0,33.17,0,44.227
c0,19.144,0,57.431,0,76.574c0,10.152,0,40.607,0,40.607c0,1.858-1.506,3.364-3.364,3.364l0,0c-1.858,0-3.364-1.506-3.364-3.364c0,0,0-30.455,0-40.607c0-19.144,0-57.432,0-76.575c0-11.057,0-44.226,0-44.226C96.636-177.015,98.142-178.521,100-178.521
L100-178.521z
;
M100,267.257c1.858,0,3.364,1.506,3.364,3.363c0,0,0,33.17,0,44.227
c0,19.143,0,57.43,0,76.574c0,10.151,0,40.606,0,40.606c0,1.858-1.506,3.364-3.364,3.364l0,0c-1.858,0-3.364-1.506-3.364-3.364
c0,0,0-30.455,0-40.606c0-19.145,0-57.432,0-76.576c0-11.057,0-44.225,0-44.225C96.636,268.763,98.142,267.257,100,267.257
L100,267.257z
;
M93.928,405.433c-0.655,6.444-0.102,9.067,2.957,11.798c0,0,8.083,5.571,16.828,3.503
c18.629-4.406,43.813,6.194,50.792,7.791c14.75,3.375,9.162,6.867,9.162,6.867c-2.412,2.258-58.328,0-73.667,0l0,0
c-1.858,0-69.995,2.133-73.667,0c0,0-3.337-2.439,6.172-5.992c11.375-4.25,52.875,8.822,47.139-9.442
c-6.333-20.167,5.226-21.514,5.226-21.514c3.435-0.915,12.78-6.663,10.923-0.546L93.928,405.433z
;
M102.242,427.569c5.348,0,14.079,0,17.462,0c0,0,17.026,0,27.504,0
c19.143,0,20.39-3.797,26.459,0c3,1.877,0,7.823,0,7.823c-2.412,2.258-58.328,0-73.667,0l0,0c-1.858,0-67.187,0-73.667,0
c0,0-4.125-4.983,0-7.823c5.201-3.58,16.085,0,23.725,0c8.841,0,20.762,0,20.762,0c3.686,0,8.597,0,19.511,0H102.242z
" />
</path>
<path fill="#a88679" d="M173.667-15.929c-46.512,0-105.486,0-147.334,0c-3.999,0-4-16.002,0-16.002
c43.566,0,97.96,0,147.334,0C177.667-31.931,177.666-15.929,173.667-15.929z">
<animate id="bizcocho_2" attributeName="d" calcMode="spline" keySplines="0 0 1 1; 0 0 1 1; 0.25 0 0.58 1" begin="relleno_1.end" dur="0.5s" fill="freeze" values="
M173.667-15.929c-46.512,0-105.486,0-147.334,0c-3.999,0-4-16.002,0-16.002
c43.566,0,97.96,0,147.334,0C177.667-31.931,177.666-15.929,173.667-15.929z
;
M173.434,445.393c-47.269,8.001-105.245,8.001-147.334,0c-3.929-0.747-0.692-16.543,3.243-15.824
c43.828,8.001,92.165,8.001,140.739,0C174.029,428.918,177.377,444.726,173.434,445.393z
;
M173.667,449.514c-47.576-5.454-102.799-5.744-147.333,0c-3.966,0.512-3.938-15.297,0-16.002
c43.683-7.823,97.646-8.026,147.333,0C177.616,434.15,177.642,449.969,173.667,449.514z
;
M173.667,451.394c-49.298,0-102.782,0-147.334,0c-3.999,0-4-16.002,0-16.002
c44.697,0,96.586,0,147.334,0C177.667,435.392,177.668,451.394,173.667,451.394z
" />
</path>
<path fill="#8b6a60" d="M101.368-73.685c0,12.164,0,15.18,0,28.519c0,22.702,0-13.661,0,8.304c0,14.48,0,18.233,0,30.512
c0,1.753-2.958,1.847-2.958,0c0-12.68,0-16.277,0-30.401c0-21.983,0,11.66,0-8.305c0-13.027,0-15.992,0-28.628
C98.411-75.883,101.368-75.592,101.368-73.685z">
<animate id="relleno_1" attributeName="d" calcMode="spline" keySplines="0 0 1 1; 0 0 1 1; 0 0 0.6 1" begin="bizcocho_1.end" dur="0.5s" fill="freeze" values="
M101.368-73.685c0,12.164,0,15.18,0,28.519c0,22.702,0-13.661,0,8.304c0,14.48,0,18.233,0,30.512
c0,1.753-2.958,1.847-2.958,0c0-12.68,0-16.277,0-30.401c0-21.983,0,11.66,0-8.305c0-13.027,0-15.992,0-28.628
C98.411-75.883,101.368-75.592,101.368-73.685z
;
M101.368,350.885c0,12.164,0,65.18,0,78.518c0,22.703,0-33.66,0-11.695c0,14.48,0,28.232,0,40.512
c0,1.753-2.958,1.847-2.958,0c0-12.68,0-26.277,0-40.402c0-21.982,0,31.66,0,11.695c0-13.027,0-65.992,0-78.627
C98.411,348.686,101.368,348.977,101.368,350.885z
;
M128.38,447.567c37.626,6.312,39.303,13.658,26.833,12.833c-22.653-1.499-13.636-0.831-23.302-0.831
c-14.48,0-17.884,0-30.163,0c-2.087,0-2.068,0-3.915,0c-13.333,0-8.963,0-23.088,0c-11.668,0-14.062,5.995-27.532,1.164
c-12.629-4.529,38.667-3.167,46.833-17.333C100.077,432.94,105.546,443.736,128.38,447.567z
;
M173.667,451.394c2.875,0,2.997,9.257,0,9.131c-22.662-0.956-32.09-0.956-41.756-0.956
c-14.48,0-17.884,0-30.163,0c-2.087,0-2.068,0-3.915,0c-13.333,0-8.963,0-23.088,0c-11.668,0-34.99-0.294-48.412,1.831
c-4.109,0.65-3.01-10.006,0-10.006C37.129,451.394,149.379,451.394,173.667,451.394z
" />
</path>
<path fill="#a88679" d="M173.667,21.571c-33.174,0-111.467,0-147.334,0c-4,0-4-16.002,0-16.002c39.836,0,105.982,0,147.334,0
C177.668,5.569,177.667,21.571,173.667,21.571z">
<animate id="bizcocho_1" attributeName="d" calcMode="spline" keySplines="0 0 1 1; 0 0 1 1; 0 0 1 1; 0.25 0 1 1; 0 0 1 1; 0.25 0 0.6 1" begin="2s" dur="0.8s" fill="freeze" values="
M173.667,21.571c-33.174,0-111.467,0-147.334,0c-4,0-4-16.002,0-16.002c39.836,0,105.982,0,147.334,0
C177.668,5.569,177.667,21.571,173.667,21.571z
;
M173.667,459.569c-33.197,16.002-110.782,16.002-147.334,0c-3.664-1.604,1.614-15.617,5.337-14.153
c40.702,16.002,94.289,16.104,136.505,0.103C171.917,444.1,177.271,457.832,173.667,459.569z
;
M171.817,475.571c-39.361-3.001-105.438-2.571-143.556,0c-3.991,0.27-7.377-14.736-3.387-15.014
c41.553-2.888,104.421-3.121,150.51-0.233C179.378,460.574,175.806,475.875,171.817,475.571z
;
M171.817,459.564c-38.8-12.188-104.504-13.762-143.556,0c-3.772,1.329-7.961-12.604-4.178-13.905
c40.864-14.064,105.114-15.52,151.918-0.973C179.822,445.874,175.634,460.762,171.817,459.564z
;
M173.667,475.571c-46.376-5.005-105.924-4.003-147.334,0c-3.981,0.385-3.479-15.421,0.479-16.002
c43.087-6.327,97.705-7.083,146.855,0.438C177.621,460.613,177.644,476,173.667,475.571z
;
M173.667,474.117c-46.376,1.866-105.638,2.01-147.334,0c-3.995-0.192-3.52-16.144,0.479-16.002
c43.794,1.55,96.341,1.541,145.723,0C176.532,457.99,177.663,473.956,173.667,474.117z
;
M173.667,475.571c-46.512,0-105.486,0-147.334,0c-3.999,0-4-16.002,0-16.002c43.566,0,97.96,0,147.334,0
C177.667,459.569,177.666,475.571,173.667,475.571z
" />
</path>
<path fill="#fefae9" d="M104.812,113.216c0,3.119-2.164,5.67-4.812,5.67c-2.646,0-4.812-2.551-4.812-5.67c0-5.594,0-16.782,0-22.375
c0-5.143,0-15.427,0-20.568c0-7.333,0-21.998,0-29.33c0-5.523,0-16.569,0-22.092c0-3.295,0-9.885,0-13.181
C95.188,2.551,97.353,0,100,0c2.648,0,4.812,2.551,4.812,5.669c0,3.248,0,9.743,0,12.991c0,5.428,0,16.284,0,21.711
c0,7.618,0,22.854,0,30.472c0,4.952,0,14.854,0,19.807C104.812,96.292,104.812,107.576,104.812,113.216z">
<animate id="crema" attributeName="d" calcMode="spline" keySplines="0 0 1 1; 0 0 1 1; 0 0 1 1; 0.25 0 1 1; 0 0 1 1; 0 0 0.58 1" begin="bizcocho_3.end" dur="2s" fill="freeze" values="
M104.812,113.216c0,3.119-2.164,5.67-4.812,5.67c-2.646,0-4.812-2.551-4.812-5.67c0-5.594,0-16.782,0-22.375
c0-5.143,0-15.427,0-20.568c0-7.333,0-21.998,0-29.33c0-5.523,0-16.569,0-22.092c0-3.295,0-9.885,0-13.181
C95.188,2.551,97.353,0,100,0c2.648,0,4.812,2.551,4.812,5.669c0,3.248,0,9.743,0,12.991c0,5.428,0,16.284,0,21.711
c0,7.618,0,22.854,0,30.472c0,4.952,0,14.854,0,19.807C104.812,96.292,104.812,107.576,104.812,113.216z
;
M104.812,405.897c0,3.119-2.164,5.67-4.812,5.67c-2.646,0-4.812-2.551-4.812-5.67c0-5.594,0-16.782,0-22.376
c0-5.143,0-15.426,0-20.568c0-7.332,0-21.997,0-29.33c0-5.522,0-16.568,0-22.092c0-3.295,0-9.885,0-13.181
c0-3.118,2.165-5.669,4.812-5.669c2.648,0,4.812,2.551,4.812,5.669c0,3.247,0,9.743,0,12.991c0,5.428,0,16.283,0,21.711
c0,7.618,0,22.854,0,30.473c0,4.951,0,14.854,0,19.807C104.812,388.972,104.812,400.256,104.812,405.897z
;
M111.873,411.567c-3.119,0-9.226,0-11.874,0c-2.646,0-7.748,0-10.867,0c-7.086,0-12.698,0-18.292,0
c-6.592,0-12.871,7.371-19.166,3.008c-10.043-6.961-7.776-10.169,2.991-17.745c12.61-8.873,27.713,1.994,25.919-7.531
c-2.589-13.742,11.008-14.513,11.365-17.789c0.441-4.051,4.235-11.107,8.051-8.175c3.113,2.393,1.007,8.008,0,13.159
c-1.871,9.569,8.058,2.113,9.494,14.155c2.592,21.732,21.184-0.675,29.309,7.976c5.216,5.553,18.413,5.552,15.426,12.942
c-3.131,7.745-15.825-4.369-23.8,2.903C126.261,418.271,118.301,411.567,111.873,411.567z
;
M111.873,411.567c-3.119,0-9.226,0-11.874,0c-2.646,0-9.734,4.069-12.853,4.069
c-7.086,0-10.712-4.069-16.306-4.069c-6.592,0-12.12,6.013-19.166,3.008c-7.053-3.008-7.458,2.026-18.659,1.165
c-6.832-0.525-7.522-3.034-7.533-6.265c-0.037-10.336,22.073-2.452,36.613-2.628c10.234-0.124,19.856-1.439,37.905-2.102
c16.642-0.61,32.699,1.552,46.009,1.927c12.438,0.351,29.663-8.99,31.532,3.315c0.773,5.093-5.605,3.342-11.211,9.579
c-5.093,5.667-7.59-4.605-12.965-3.832c-8.269,1.189-14.962-8.537-22.937-1.265C126.261,418.271,118.301,411.567,111.873,411.567z
;
M110.946,413.652c-2.904-1.137-8.405-2.748-12.446-0.97c-6.099,2.685-7.273,10.358-13.253,8.242
c-7.843-2.775-8.953-5.008-14.546-5.01c-24.653-0.011-4.849,26.507-18.264,26.507c-12.377,0,5.791-33.537-19.422-26.682
c-7.703,2.095-9.806-0.942-9.817-4.173c-0.037-10.336,24.357-4.544,38.897-4.72c10.234-0.124,19.856-1.439,37.905-2.102
c16.642-0.61,32.699,1.552,46.009,1.927c12.438,0.351,28.973-8.865,31.532,3.315c1.449,6.896,0.318,15.624-3.874,15.624
c-7.619,0-1.788-15.192-19.243-7.111c-7.581,3.51-15.963-9.738-26.669,1.066C120.644,426.744,118.381,416.561,110.946,413.652z
;
M111.547,413.9c-2.969-0.956-8.775-0.949-13.167-0.5c-14.667,1.5-8.325,16.508-14.667,16.666
c-6.667,0.166-0.167-13.5-13.013-14.151c-30.471-1.545-5.572,46.651-18.987,46.651c-12.377,0,10.333-50.166-18.667-44.5
c-7.835,1.531-9.537-1.417-9.548-4.647c-0.037-10.336,23.675-5.177,38.215-5.353c10.234-0.124,20.618-1.671,38.667-2.333
c16.642-0.61,32.023,1.458,45.333,1.833c12.438,0.351,33.819-8.431,33.199,4.001c-0.532,10.666,0.414,26.166-5.245,25.833
c-7.606-0.447-2.954-31.5-19.243-18.899c-7.985,6.177-17.658-5.969-27.377,5.732C118.88,434.066,121.38,417.067,111.547,413.9z
;
M111.547,415.233c-6.667-0.834-9.667,4.667-13.833,3.333c-19.649-6.291-8.158,22.176-14.5,22.334
c-6.667,0.166,2.833-18-13.333-22.167c-29.544-7.615-9.667,43.833-20.167,43.833c-10.333,0,8.004-55.006-16.833-39
c-7.5,4.833-9.508-3.78-9.299-7.004c0.799-12.329,23.592-7.153,38.132-7.329c10.234-0.124,20.238-1.505,38.287-2.167
c16.642-0.61,32.903,1.125,46.213,1.5c12.438,0.351,35.058-5.579,31.863,6.451c-5.532,20.833,1.25,28.216-4.409,27.883
c-7.606-0.447-6.058-37.895-20.62-23.333c-10.167,10.166-15.972-0.747-25,12C119.547,443.568,121.798,416.515,111.547,415.233z
" />
</path>
<rect x="10" y="475.571" fill="#fefae9" width="180" height="4" />
</svg>
<div class="text">
<h1>生日快乐!</h1>
<p>大宝贝蛋子~</p>
</div>
</body>
</html>