技术概览
本文将通过以下技术的结合的实现飞机按路线航行的模拟动画效果
- SVG
- Css Motion Path
- keyframes
效果预览
✈️航行预览(tip:由于是视频转gif生成的动图,效果有些卡顿,原视频很流畅)
流畅动画下载
实现思路
- 为了便于计算飞机航行的轨迹,可以画出网格线辅助;
- 添加飞机,然后通过svg的path元素画出航行的直线路径;
<svg class="test-svg">
<path class="path" d="M 80 80 L 160 160 L 240 80 L 320 0 L 400 80" fill="transparent" stroke="rgba(255,0,0,0.5)" />
</svg>
效果如下所示:
- 然而平滑生动的动画效果当然不能是这种直线的运动,所以我们按照这条路径,写出三次贝塞尔曲线,形成平滑的路径:
<svg class="test-svg">
<path class="path" d="M 80 80 L 160 160 L 240 80 L 320 0 L 400 80" fill="transparent" stroke="rgba(255,0,0,0.5)" />
<!-- add 贝塞尔曲线 -->
<path d="M 80 80 C 160 160 160 160 240 80 S 320 0 400 80" fill="transparent" stroke="rgba(0,0,0,0.5)" stroke-dasharray="5, 5"></path>
</svg>
关于贝塞尔曲线的画法,可以参考深度掌握SVG路径path的贝塞尔曲线指令 一文,效果如下所示:
✈️飞机会按这条虚线流畅飞行,那么如何让飞机按照这条航线飞行呢,这就需要用到CSS Motion Path中offset-path属性了,CSS Motion Path 规范主要包含以下几个属性:
- offset-path:接收一个 SVG 路径,类似于svg中的path,指定运动的几何路径;
- offset-distance:控制当前元素基于 offset-path 运动的距离;
- offset-anchor:指定当前元素的哪一个点沿路径运动;
- offset-rotate:定义沿 offset-path 定位时元素的方向,元素的角度朝向;
通过使用offset-path规定运动路径,即我们上面画出的贝塞尔曲线(虚线),offset-distance规定运动的距离(到哪里了)结合keyframes,再将运动的点设置在元素中心,即可实现:
<!-- 飞机✈️ -->
<div class="fly">
<img style="width: 40px;" src="../src/static/plane.svg" alt="">
</div>
.fly {
position: absolute;
top: 40px;
left: 0px;
width: 40px;
height: 40px;
border: 1px dashed rgba(50, 0, 0, 0.5);
offset-path: path("M 80 80 C 160 160 160 160 240 80 S 320 0 400 80");
offset-anchor: 20px 20px;
animation: move 4000ms infinite linear;
}
为了保证飞机在过弯时角度变换的流畅性,需要计算入弯和出弯时角度的变化,在keyframes动画中需要计算写出对应的状态:
@keyframes move {
0% {
offset-rotate: 90deg;
offset-distance: 0%;
}
18.7% {
offset-rotate: 90deg;
offset-distance: 18.7%;
}
25% {
offset-rotate: 45deg;
offset-distance: 25%;
}
31.2% {
offset-rotate: 0deg;
offset-distance: 31.2%;
}
68.7% {
offset-rotate: 0deg;
offset-distance: 68.7%;
}
75% {
offset-rotate: 45deg;
offset-distance: 75%;
}
81.2% {
offset-rotate: 90deg;
offset-distance: 81.2%;
}
100% {
offset-rotate: 90deg;
offset-distance: 100%;
}
}
兼容性
主要取决于浏览器对于Css Motion Path的支持chrome支持不错,不过在safari上就不能使用,见下表所示: