以下是一份逐步拆解教程,带你从零理解并复刻这个牛顿摆(Pendulum of Newton)动画效果,这是一个经典的物理演示模型,现在通过纯 HTML 和 CSS 实现出来,视觉效果炫酷、结构简洁。
🎯 动画效果说明
- 页面中央悬挂了五根线,每根线下方挂着一个小球。
- 最左和最右的小球依次以一定角度摆动。
- 中间三颗球静止,模仿现实中“动量守恒”的经典效果。
🧱 第 0 步:项目结构
newton-pendulum/
├── index.html # HTML结构
└── style.css # 样式与动画
🔤 第 1 步:HTML 结构
从 index.html
中可以看到如下结构【已简化注释】:
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>牛顿摆</title>
<link rel="stylesheet" href="style.css" type="text/css" media="all">
<link href="https://fonts.googleapis.com/css?family=Lato:400,700" rel="stylesheet">
</head>
<body>
<div class="pendulo">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</body>
</html>
✅ 说明
.pendulo
是牛顿摆的总容器。- 5 个
<span>
表示 5 根线,每根线下面有一个球(通过 CSS 中的::before
实现)。
🎨 第 2 步:页面居中 + 背景色设置
在 style.css
中,先看看 body
和 .pendulo
的样式:
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: #2c3e50; /* 深蓝背景 */
}
.pendulo {
display: flex;
border-top: 10px solid white; /* 顶部横杆 */
}
关键点
- 使用
flex
实现内容居中。 border-top
让.pendulo
看起来像是“挂球的横梁”。
⚙️ 第 3 步:定义线条和球体
.pendulo span {
display: block;
width: 3px; /* 细线 */
height: 300px; /* 绳子长度 */
background-color: white;
margin: 0 29px; /* 线与线之间间距 */
position: relative;
transform-origin: top; /* 旋转中心为上端 */
}
说明
- 每根线是一个细长的
div
。 - 设置了
transform-origin: top
,使动画时以顶部为旋转中心。
⚪ 第 4 步:添加球体(使用伪元素)
.pendulo span:before {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 60px;
height: 60px;
border-radius: 50%; /* 圆形 */
background-color: white;
transform: translateX(-50%);
}
✨ 原理
::before
是挂在每根绳子底部的球。width: 60px
+border-radius: 50%
形成一个白色圆形。transform: translateX(-50%)
让球体居中于线条正下方。
🧩 第 5 步:添加左右摆动动画
为第一个和最后一个 span
添加动画:
.pendulo span:first-child {
animation: left-arm 2s ease-in infinite;
}
.pendulo span:last-child {
animation: right-arm 2s ease-in infinite 1s;
}
⏱️ 动画延迟
left-arm
动画立即开始。right-arm
动画延迟1s
开始,模拟能量从左球传递到右球的过程。
🎞️ 第 6 步:定义关键帧动画
左球动画
@keyframes left-arm {
0% { transform: rotate(0deg); }
25% { transform: rotate(60deg); }
50% { transform: rotate(0deg); }
100% { transform: rotate(0deg); }
}
右球动画
@keyframes right-arm {
0% { transform: rotate(0deg); }
25% { transform: rotate(-60deg); }
50% { transform: rotate(0deg); }
100% { transform: rotate(0deg); }
}
💡 分析
- 每个动画都是 2 秒一轮:
- 0%~25%:摆动到最大角度(60° 或 -60°)。
- 25%~50%:返回中间(静止)。
- 50%~100%:保持不动。
- 中间 3 个球没有动画,模拟现实中的受力后“保持静止”。
🔁 整体动画节奏
- 每两秒一次完整循环:
- 第 1 秒:左球摆动,撞击中间球。
- 第 2 秒:右球摆动,作为动量传递的结果。
- 循环往复,展示真实的牛顿摆动作。
🧪 可拓展方向
颜色变化
background-color: crimson; /* 红色球体 */
增加阴影或发光
box-shadow: 0 0 10px white;
添加真实晃动曲线(贝塞尔曲线)
- 使用
cubic-bezier()
替代ease-in
,可以模拟更真实物理轨迹。
- 使用
交互性
- 使用 JavaScript 添加点击触发、暂停等功能。
✅ 总结
技术点 | 应用说明 |
---|---|
flexbox |
页面元素居中 |
transform |
通过旋转实现绳子摆动 |
::before |
创建附着在元素上的球体 |
animation-delay |
控制动画交错,让左右球交替摆动 |
keyframes |
自定义动画流程,控制角度变化与节奏 |