实现思路:
设计波浪形状、实现波浪的动画效果、设置多层波浪的交错动画。
1. 设计波浪形状
波浪的形状是通过SVG(可缩放矢量图形)来实现的。SVG是一种基于XML的矢量图形格式,适合绘制分辨率独立的图形。使用<path>
元素来定义波浪的路径。
定义路径数据:路径数据使用d
属性,它包含了一系列的命令和参数,这些命令描述了如何绘制图形。常用的命令包括:M x,y
: 移动到指定坐标,设定路径的起点。c dx1,dy1 dx2,dy2 dx,dy
: 画贝塞尔曲线,起点是上一个坐标,终点是由dx,dy
确定,相对前一个坐标。dx1,dy1
和dx2,dy2
定义控制点的相对位置。
本篇使用的数据路径如下:
<path id="gentle-wave" d="M-160 30c30 0 58-3 88-3s 58 3 88 3 58-3 88-3 58 3 88 3 v44h-352z" />
注:
1.M-160 30
: 从起点(-160, 30)开始。
2.c30 0 58-3 88-3
: 画出一段平缓的波浪。
3.s 58 3 88 3
: 继续绘制波浪,s
命令指定与前一个控制点镜像的控制点。
4.v44
: 垂直向下移动44个单位。
5.h-352
: 水平向左绘制352个单位,闭合路径。
2. 实现波浪的动画效果
为了使波浪动起来,使用CSS动画。通过在多个<use>
元素中引用相同的<path>
,并给这些元素设置不同的动画属性,可以模拟波浪的运动。
动画属性设置: animation: move 4s cubic-bezier(.55, .5, .45, .5) infinite
: 为波浪设置动画。move
是动画的名称,4s
表示动画周期为4秒,cubic-bezier
函数用于定义动画的速度曲线,infinite
表示动画将无限循环。
@keyframes move {
0% {
transform: translateX(-90px);
}
100% {
transform: translateX(85px);
}
}
动画实现:transform: translateX(...)
用于在水平方向上移动波浪,制造出波动的效果。
3. 多层波浪的交错动画
通过设置不同的动画延迟和持续时间,可以使各层波浪看起来交错波动,从而增加画面的层次感。
设置不同的透明度和动画时间:fill-opacity
: 控制波浪的透明度。animation-delay
: 设置动画的开始延迟时间,使各层波浪的运动出现层次。animation-duration
: 控制动画的周期长度,让波浪看起来更自然。
.waves use {
fill-opacity: 1; /* 默认透明度 */
}
/* 第一层波浪 */
.waves use:nth-child(1) {
animation-delay: -2s; /* 动画延迟时间 */
animation-duration: 7s; /* 动画周期 */
fill: rgba(100, 255, 155, 0.7); /* 颜色及透明度设置 */
}
/* 第二层波浪 */
.waves use:nth-child(2) {
animation-delay: -3s;
animation-duration: 10s;
fill: rgba(100, 255, 155, 0.5);
}
/* 第三层波浪 */
.waves use:nth-child(3) {
animation-delay: -4s;
animation-duration: 13s;
fill: rgba(100, 255, 155, 0.3);
}
/* 第四层波浪 */
.waves use:nth-child(4) {
animation-delay: -5s;
animation-duration: 20s;
fill: rgba(100, 255, 155, 0.9);
}
成品展示
转gif有瑕疵,真实效果请自行运行查看
完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
.container {
position: relative;
width: 200px;
height: 200px;
overflow: hidden;
border-radius: 100px;
background: radial-gradient(at center, skyblue, lightblue, white);
display: flex;
align-items: flex-end;
border: 1px solid #8f8f8f;
box-shadow: 1px 1px 3px #66666679;
}
.waves {
position: relative;
width: 100%;
height: 20vh;
margin-bottom: -7px;
min-height: 100px;
max-height: 150px;
}
.parallax>use {
animation: move 4s cubic-bezier(.55, .5, .45, .5) infinite;
}
@keyframes move {
0% {
transform: translateX(-90px);
}
100% {
transform: translateX(85px);
}
}
.waves use {
fill-opacity: 1;
}
.waves use:nth-child(1) {
animation-delay: -2s;
animation-duration: 7s;
}
.waves use:nth-child(2) {
animation-delay: -3s;
animation-duration: 10s;
}
.waves use:nth-child(3) {
animation-delay: -4s;
animation-duration: 13s;
}
.waves use:nth-child(4) {
animation-delay: -5s;
animation-duration: 20s;
}
</style>
</head>
<body>
<div class="container">
<div>
<svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto">
<defs>
<path id="gentle-wave" d="M-160 30c30 0 58-3 88-3s 58 3 88 3 58-3 88-3 58 3 88 3 v44h-352z" />
</defs>
<g class="parallax">
<use xlink:href="#gentle-wave" x="48" y="1" fill="rgba(100,255,155,0.7)" />
<use xlink:href="#gentle-wave" x="48" y="1" fill="rgba(100,255,155,0.5)" />
<use xlink:href="#gentle-wave" x="48" y="2" fill="rgba(100,255,155,0.3)" />
<use xlink:href="#gentle-wave" x="48" y="3" fill="rgba(100,255,155,0.9)" />
</g>
</svg>
</div>
</div>
</body>
</html>