CSS 实现小球抛物线运动的动画效果
在网页开发中,利用纯 CSS 模拟物理运动效果是一种常见且高效的方式。抛物线运动(如平抛运动)是由水平方向的匀速直线运动和竖直方向的匀加速直线运动合成。CSS 动画无法直接计算每一帧的物理坐标,但我们可以通过分层动画或组合 timing function 来实现逼真的抛物线轨迹。下面将详细介绍如何使用 CSS 动画实现一个小球沿抛物线运动的完整方案。
实现原理
平抛运动的特征是:水平方向速度恒定,竖直方向受重力做匀加速运动。CSS 中的 animation 允许为不同属性分别定义动画。我们可以将抛物线拆解为两个独立的动画:
- 水平方向:使用
left或transform: translateX()结合linear缓动函数,模拟匀速运动。 - 竖直方向:使用
top或transform: translateY()结合ease-in或自定义贝塞尔曲线(如cubic-bezier(0.42, 0, 1, 1)),模拟自由落体的加速效果。
为了简单易懂,这里采用两层 div 嵌套的方式:外层容器控制水平移动,内层小球控制垂直移动。这样水平运动和垂直运动互不干扰,分别应用不同的动画即可。
完整代码示例
以下是一个完整的 HTML 文档,它创建了一个蓝色小球从左向右平抛运动的动画效果。小球落地后停止运动。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS抛物线运动</title>
<style>
/* 外层容器:水平匀速运动 */
.moving-container {
position: absolute;
top: 50px;
left: 0;
width: 60px;
height: 60px;
animation: moveHorizontal 2s linear forwards;
}
/* 内层小球:垂直匀加速运动(自由落体) */
.ball {
width: 60px;
height: 60px;
background: radial-gradient(circle at 30% 30%, #66b3ff, #1a8cff);
border-radius: 50%;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
animation: dropDown 2s ease-in forwards;
}
/* 水平方向动画:从左侧移动到右侧 */
@keyframes moveHorizontal {
0% {
left: 0;
}
100% {
left: calc(100% - 60px);
}
}
/* 垂直方向动画:从顶部自由落体到地面(借助父元素定位模拟竖直向下) */
@keyframes dropDown {
0% {
top: 0;
}
100% {
top: calc(100vh - 110px); /* 留出顶部 margin,适应视口 */
}
}
/* 辅助样式:为显示轨迹,给背景添加参考线(可选) */
body {
background: #f5f7fa;
margin: 0;
height: 100vh;
overflow: hidden;
}
/* 地面标记(可选) */
.ground {
position: absolute;
bottom: 50px;
left: 0;
width: 100%;
height: 2px;
background: #333;
}
</style>
</head>
<body>
<div class="ground"></div>
<div class="moving-container">
<div class="ball"></div>
</div>
</body>
</html>代码说明
- 结构拆分:
.moving-container负责水平方向的移动,动画moveHorizontal让它的left值从 0 到calc(100% - 60px),即从左侧边界运动到右侧边界,时间 2 秒,缓动函数为linear(匀速)。 - 垂直运动:
.ball内部设置动画dropDown,控制top值从 0 到calc(100vh - 110px),使其看起来像是从高处下落。缓动函数选择ease-in,速度由慢变快,模拟自由落体的加速过程。 - 坐标系定义:注意外层容器和内层小球都使用了
position: absolute,且外层没有设置top,默认为 0。内层小球的top从 0 开始运动,相对于其父容器(外层)。因此,小球在垂直方向上是相对于外层容器的偏移,而外层容器本身在水平方向移动,从而合成平滑的抛物线轨迹。 - 结束状态:两个动画都设置为
forwards,使小球停留在终点位置,模拟落地后的静止。
优化与扩展
上述方法简单直观,但若希望轨迹更加精确,也可以使用单个元素结合 transform 的 translate 属性,利用多个关键帧插值模拟弧线。以下是一个使用 @keyframes 直接定义多个中间点实现抛物线效果的示例(适用于简单场景):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>抛物线 - 关键帧插值</title>
<style>
.ball-single {
position: absolute;
left: 0;
top: 0;
width: 50px;
height: 50px;
background: #ff6b6b;
border-radius: 50%;
animation: parabola 2s ease-in-out forwards;
}
@keyframes parabola {
0% {
transform: translate(0, 0);
}
25% {
transform: translate(100px, 80px);
}
50% {
transform: translate(200px, 120px);
}
75% {
transform: translate(300px, 80px);
}
100% {
transform: translate(400px, 0);
}
}
body {
background: #f0f4ff;
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: flex-start;
padding-top: 50px;
}
</style>
</head>
<body>
<div class="ball-single"></div>
</body>
</html>这个示例通过手动设置多个关键帧的位移坐标,模拟一条近似抛物线的路径。但它不够物理真实,需要手动调整坐标点。对于需要严格物理模拟的场景,推荐使用 JavaScript 配合 requestAnimationFrame 计算每一帧的位置,但纯 CSS 方案在简单演示中已经足够。
总结
通过拆分水平和垂直方向的动画,并分别赋予不同的缓动函数,可以轻松用纯 CSS 实现逼真的抛物线运动效果。这种方法不需要 JavaScript 计算,代码简洁,性能优秀。读者可以根据实际需要调整动画时长、距离以及起始位置,还可以加入 transform: scale 或 opacity 等来丰富动画细节。希望本文的示例和思路能够对您的动画开发有所启发。