一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情。
stroke-dasharray与stroke-dashoffset
stroke-dasharray
stroke-dasharray用于创建虚线,值可以有多个。
stroke-dasharray为一个参数时stroke-dasharray = '10' 表示:实线10,间距也是10;两个参数或者多个参数时,如:stroke-dasharray = '10, 5' 表示:实线10,间距5,依次循环。
stroke-dashoffset
stroke-dashoffset是偏移的意思。
这个属性是相对于起始点的偏移,正数偏移x值的时候,相当于往左移动了x个长度单位,负数偏移x的时候,相当于往右移动了x个长度单位。
做一个动画:线段从无到有,由短变长
第一步:设置stroke-dasharray实线长度等于当前svg的宽度,间隔的长度大于或者等于svg宽度
<svg>
<line id="line" x1="30" y1="30" x2="300" y2="30" stroke-width="20" stroke="red" stroke-dasharray="300"/>
</svg>
第二步:设置stroke左移300单位(stroke-dashoffset:300),也就是刚好隐藏了实线,可视区域内变成了300单位的间隔。
第三步:当鼠标移入的时候,使offset由300变成0,就实现了动图中的效果:
svg:hover #line {
stroke-dashoffset: 0;
}
#line {
transition: all 2s;
}
<svg>
<line
id="line"
x1="30"
y1="30"
x2="300"
y2="30"
stroke-width="20"
stroke="red"
stroke-dasharray="300"
stroke-dashoffset="300"
/>
</svg>
svg的transform 变换
- translate 位移
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="0" y="0" width="50" height="50" transform="translate(10,10)" />
</svg>
- rotate 旋转
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="0" y="0" width="50" height="50" transform="translate(50,50) rotate(30)" />
</svg>
- scale 缩放
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="0" y="0" width="50" height="50" transform="translate(50,50) scale(.5)" />
</svg>
环形进度条
.circle {
animation: circle 5s linear infinite;
transform-origin: center center;
}
@keyframes circle {
from {
stroke-dasharray: 0 1069;
}
to {
stroke-dasharray: 1069 0;
}
}
<svg width="440" height="440" viewbox="0 0 440 440">
<circle
cx="220"
cy="220"
r="170"
stroke-width="50"
stroke="#D1D3D7"
fill="none"
></circle>
<circle
class="circle"
cx="220"
cy="220"
r="170"
stroke-width="50"
stroke="#00A5E0"
fill="none"
// 从顶部开始
transform="rotate(270)"
/>
</svg>
LOGO 描边
- 下载任意 SVG 格式的 LOGO
- 获取 path 长度
const path = document.getElementById('taobao-path')
const pathLen = path.getTotalLength()
- 添加描边样式和动画
.taobao-path {
fill: none;
stroke: #333;
stroke-width: 1;
animation: taobao 5s linear infinite forwards;
}
@keyframes taobao {
from {
stroke-dasharray: 8974;
stroke-dashoffset: 8974;
}
to {
stroke-dasharray: 8974;
stroke-dashoffset: 0;
}
}
<svg>
<path
id="taobao-path"
class="taobao-path"
d="M512 64l338.773333 76.330667A85.333333 85.333333 0 0 1 917.333333 223.573333v407.253334a170.666667 170.666667 0 0 1-86.506666 148.48l-276.757334 156.842666a85.333333 85.333333 0 0 1-84.138666 0L193.173333 779.285333A170.666667 170.666667 0 0 1 106.666667 630.826667V223.573333a85.333333 85.333333 0 0 1 66.56"
></path>
</svg>
SMIL
SMIL 全称 Synchronized Multimedia Integration Language,它允许我们通过 HTML 标签实现动画效果,它可以用于:
- 实现过渡动画
- 实现补间动画
- 路径运动动画(CSS3无法实现)
SMIL 包含以下标签:
<set>
<animate>
<animateTransform>
<animateMotion>
为什么要用 SMIL?
实现动画的全新方式:
- 无需 CSS
- 无需 JS
- 几个标签轻松实现复杂动画,它不香吗?
一个元素的动画属性
- attributeName: 变动的属性的属性名
- from: 变动的初始值
- to: 变动的终值
- dur: 动画的持续时间
set标签
实现属性的延迟设置,这样设置后,就每隔1s移动一端距离,不会有补间的动画,非常生硬。
<svg width="400" height="400">
<rect x="0" y="0" width="100" height="100" fill="red">
<set attributeName="x" attributeType="XML" to="10" begin="1s" />
<set attributeName="x" attributeType="XML" to="20" begin="2s" />
<set attributeName="x" attributeType="XML" to="30" begin="3s" />
<set attributeName="x" attributeType="XML" to="40" begin="4s" />
<set attributeName="x" attributeType="XML" to="50" begin="5s" />
</rect>
</svg>
animation标签
如果你想在同一个元素里变动更多的属性,只要添加更多的元素
<svg width="500" height="200" viewBox="0 0 500 200">
<circle cx="0" cy="0" r="30" fill="blue" stroke="black" stroke-width="1">
<animate
attributeName="cx"
from="0"
to="200"
dur="5s"
repeatCount="indefinite"
/>
<animate
attributeName="cy"
from="0"
to="200"
dur="5s"
repeatCount="indefinite"
/>
</circle>
</svg>
animateTransform 标签
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="0" y="0" width="60" height="60" fill="red">
<animateTransform
attributeName="transform"
begin="0s"
dur="3s"
type="scale"
from="1"
to="2"
repeatCount="indefinite"
/>
</rect>
</svg>
animateMotion 标签
可以自定义轨迹,然后沿着轨迹运动,这是css动画无法实现的
案例一:按 path 轨迹运动的正方形
rotate:设置沿轨迹交汇处转弯处的运动情况。小方块rect会沿着path="M 10 10 L 110 10 L 110 110 L 10 110 Z"做运动。
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="0" y="0" width="10" height="10" fill="red">
<animateMotion
path="M 10 10 L 110 10 L 110 110 L 10 110 Z"
dur="5s"
rotate="auto"
fill="freeze"
repeatCount="indefinite"
/>
</rect>
<path
id="motion-path"
d="M 10 10 L 110 10 L 110 110 L 10 110 Z"
fill="none"
stroke="green"
/>
</svg>
案例二:混合动画
需求:小方块沿轨迹运动后,需要按原路返回。
begin开始的时间可以是上一次运动结束后再开始,animateMotion需要加上id。begin可以用分号分割多个值。
<svg viewBox="0 0 200 200" width="200" height="200">
<rect x="0" y="0" rx="0" ry="0" width="10" height="10" fill="red">
<animateMotion
id="forward-rect"
path="M 10 10 L 110 10 L 110 110 L 10 110"
dur="2s"
rotate="0"
fill="freeze"
begin="0; backward-rect.end + 0.5s"
/>
<animateMotion
id="backward-rect"
path="M 10 110 L 110 110 L 110 10 L 10 10"
dur="2s"
rotate="0"
fill="freeze"
begin="forward-rect.end + 0.5s"
/>
</rect>
<path
d="M 10 10 L 110 10 L 110 110 L 10 110"
fill="none"
stroke-width="1"
stroke="blue"
/>
</svg>
上面两个动画可以形成一个无限循环的效果,首先forward-rect动画开始,第二个动画在第一个动画结束后0.5s开始运动(forward-rect.end + 0.5s),然后第一个动画在backward-rect结束后0.5s再开始运动。
案例三:点击变色或位移
begin还可以不止可以用时间来开始,还可以用click等事件进行开始,begin="rect1.click" 点击rect1的时候开始动画。
注意animate有个作用域的问题,如果放在rect的内部,那么只会对rect进行动画。如果放在svg下面,那么就对svg下面所有的图形进行动画。
<svg viewBox="0 0 200 200" width="200" height="200">
<g id="rect1">
<rect x="0" y="0" rx="0" ry="0" width="100" height="100" fill="red">
<animate
attributeType="XML"
attributeName="fill"
from="red"
to="green"
begin="rect1.click"
dur="2s"
fill="freeze"
/>
</rect>
</g>
<animateTransform
attributeType="XML"
attributeName="transform"
type="translate"
from="0, 0"
to="50, 50"
begin="rect1.click"
dur="2s"
fill="freeze"
/>
<rect x="0" y="100" width="100" height="100" fill="blue">
<animate
attributeType="XML"
attributeName="fill"
from="blue"
to="green"
begin="rect1.click"
dur="2s"
fill="freeze"
/>
</rect>
</svg>