1. 项目概述与效果演示
先说结论:这次要做的是一个纯用HTML和CSS实现的钟摆动画,不需要一行JavaScript。它解决的核心问题是——帮前端入门的人把CSS动画、transform变换、transform-origin中心点这三个最绕的知识点一次性打通。相比市面上那些要么纯讲理论、要么直接甩源码的教程,这篇会把每一步为什么这么做、踩过的坑是什么都写清楚。
适合谁看?刚学完HTML和CSS基础标签、想进阶动画的初学者;准备前端面试、需要快速掌握CSS动画核心概念的人;以及想给自己的个人主页加一个有趣小动效的开发者。
先看最终效果:页面上有一个倒挂的摆动杆,底部吊着一个圆球,整个结构像老式座钟的钟摆一样,从左边晃到右边、再从右边晃回左边,节奏感十足。摆动的核心物理效果是:经过最低点时速度最快,到达两端顶点时速度最慢、短暂停滞,然后折返。这是仿真钟摆和普通匀速摇动最本质的区别,也是这个项目里最有技术含量的一部分。
再说一遍:本体只有两个文件(或者一个HTML文件内联搞定),总共不到120行代码。你在浏览器里直接双击就能打开看效果,不需要安装任何框架、依赖和构建工具。真正做到了“复制就能跑、跑完就能改”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 整体设计与思路拆解
2.1 为什么选HTML+CSS而不是加一点JavaScript
很多第一次看到这个效果的人会问:不就一个左右摆动吗,用JS的定时器改角度不就行了?确实可以,但用CSS动画有一个JS很难替代的优势——浏览器原生合成器优化。CSS的transform和opacity动画会走GPU渲染管线,不触发重排和重绘,在低端手机上也极其顺滑。而用JS去改style.left或者style.transform,每一帧都会触发布局计算,性能差一个量级。
更重要的是,这个项目的教学定位决定了它要去掉所有外围噪音。加了JS,反而把真正的重点——CSS动画的keyframes关键帧、animation-timing-function缓动函数、transform-origin旋转中心——给冲淡了。纯CSS方案能让你更聚焦。
2.2 结构选型:一个容器加两个子元素
看最终效果,钟摆其实分三部分:顶部的固定横梁、中间的摆动杆、底部的摆锤。但在DOM结构上,我只需要两层:
html复制<div class="clock-pendulum">
<div class="pendulum-arm"></div>
<div class="pendulum-bob"></div>
</div>
为什么要两层而不是三层?因为横梁只是背景装饰,不参与摆动,可以不放进结构。真正需要动画的只有“摆”这个整体。把pendulum-arm和pendulum-bob都放在clock-pendulum里,然后让clock-pendulum整体旋转,这样杆和球就是一体运动的,不需要分别计算各自的坐标,这是整个布局最省心的地方。
2.3 旋转中心点:钟摆动画最关键的一步
CSS里让元素旋转,默认是绕元素的几何中心转。但钟摆的物理特征是绕悬挂点转——也就是摆杆的最顶端。如果你不处理这个,摆出来的效果会像个陀螺一样绕着杆子中间打转,完全不是钟摆。
这里就要用到 transform-origin 属性了。我把摆动容器的中心点设置到顶部的悬挂点:
css复制.clock-pendulum {
transform-origin: 50% 0%;
}
50% 0% 表示:水平方向在容器正中,垂直方向在容器最顶端。这样整个钟摆就会像被一根钉子钉在天花板上一样,绕着那个钉子往复摆动,物理直觉瞬间就对了。
这块是第一大坑点。不用心体会的话,你写出来的动画要么原地打转、要么绕着一个奇怪的点摇晃。理解了 transform-origin,CSS动效里至少一半的疑难杂症都解决了。
3. 核心细节解析与实操步骤
3.1 从零搭HTML骨架:最小可用结构
先建一个文件,名字随意,比如 pendulum.html。最外层骨架如下:
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>
/* 后面所有样式都写在这里 */
</style>
</head>
<body>
<div class="scene">
<div class="clock-pendulum">
<div class="pendulum-arm"></div>
<div class="pendulum-bob"></div>
</div>
</div>
</body>
</html>
这里多加了一个 .scene 场景容器。它承担两个职责:一是让钟摆整体在页面居中,二是作为裁切边界,防止钟摆摆动到边界外产生横向滚动条。这属于经验之谈,很多初学者不写这层,结果动画一跑页面左右晃,还以为是自己代码写错了。
3.2 页面级样式:让钟摆站对位置
接下来写基础样式。这里我用Flex布局把钟摆整个放到视口中央:
css复制* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #1a1a2e;
font-family: system-ui, sans-serif;
}
.scene {
position: relative;
width: 300px;
height: 400px;
overflow: hidden;
border-bottom: 3px solid #e0c068;
}
几点说明:
body用了min-height: 100vh而不是height: 100vh,目的是在移动端浏览器地址栏伸缩时避免布局塌陷。.scene设了固定宽高,内部overflow: hidden,这样摆到最远点时也不会让页面出现横向滚动。宽度300px、高度400px是我试下来比较舒服的比例,杆长和摆幅都会在这个范围内取值。- 底部那条
border-bottom: 3px solid #e0c068是模拟“地面”或“底座”,给钟摆一个视觉参照系。没有它,悬空的摆动看起来会有点飘。
3.3 横梁装饰:用伪元素画固定结构
钟摆顶部应该有一个固定横梁,不然整个结构看起来就像凭空吊着一根线。但我不想为了它额外加DOM,所以用 ::before 伪元素来实现:
css复制.scene::before {
content: "";
position: absolute;
top: 40px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 8px;
background: #e0c068;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.4);
}
这里的 top: 40px 不是随便拍的。钟摆的悬挂点我设定在 .clock-pendulum 的顶部,也就是离 .scene 顶部约60px的位置。横梁放在40px处,刚好和悬挂点错开一点距离,视觉上就像钟摆挂在这根横梁的中央,有空间层次感。
3.4 摆锤与摆杆:绝对定位让结构稳稳不乱
接下来是核心的 .clock-pendulum:
css复制.clock-pendulum {
position: absolute;
top: 60px;
left: 50%;
width: 4px;
height: 260px;
margin-left: -2px;
transform-origin: 50% 0%;
animation: swing 2s ease-in-out infinite;
}
很多人会漏掉 margin-left: -2px 这一步。因为 .clock-pendulum 定位在 left: 50%,意思是它的左边界在容器正中,而它的宽度只有4px,如果不往左回移2px,整个摆会偏向中心点右侧2像素。虽然只差2像素,但在来回摆动时肉眼能明显感觉到不对称。margin-left: -2px 配合 width: 4px 正好让容器中心对齐父级中心。
height: 260px 是摆杆长度。注意这里的容器高度包含了摆锤的位置——我打算让摆锤绝对定位在容器底部,所以260px是“悬挂点到摆锤圆心的距离”加“摆锤半径”。
然后是摆杆本身:
css复制.pendulum-arm {
position: absolute;
top: 0;
left: 50%;
width: 4px;
height: 220px;
margin-left: -2px;
background: linear-gradient(to bottom, #e0c068, #b8943f);
border-radius: 2px;
}
这里摆杆是从容器最顶端开始,向下延伸220px,底部留出约40px给摆锤。为什么不用容器本身的背景来当摆杆,而是单独用子元素?因为容器要做旋转动画,如果直接用容器背景当摆杆,那 transform-origin: 50% 0% 时背景也跟着绕顶旋转,这没问题;但麻烦的地方在于摆锤中心点不好对齐。分开来做,摆锤可以独立定位在容器底部,而摆杆固定在顶部,互不干扰,逻辑上更清晰。
3.5 摆锤:用伪元素画一个圆润的球体
摆锤我用了 .pendulum-bob 这个空元素,配合 ::before 和 ::after 两个伪元素来实现立体感:
html复制<div class="pendulum-bob"></div>
css复制.pendulum-bob {
position: absolute;
bottom: 0;
left: 50%;
width: 44px;
height: 44px;
margin-left: -22px;
}
.pendulum-bob::before {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle at 35% 30%, #f5d76e, #c9a035 60%, #7a5c1a);
border-radius: 50%;
box-shadow:
0 4px 8px rgba(0,0,0,0.5),
inset 0 -4px 6px rgba(0,0,0,0.2);
}
.pendulum-bob::after {
content: "";
position: absolute;
left: 50%;
top: 0;
width: 3px;
height: 100%;
transform: translateX(-50%);
background: linear-gradient(to bottom, #e0c068, #b8943f);
}
这里有两个细节值得说道:
margin-left: -22px和宽度44px配合,让摆锤水平居中。49px的球,中心点落在容器中心线上。::after伪元素画的是摆锤上方与摆杆衔接的那一小段金属杆。因为摆杆本身高度到220px就停了,而摆锤容器从底部往上算起,中间其实有一段视觉空隙。用::after填上,视觉上就是一根完整的杆从顶部贯穿到球体中心。
inset: 0 是 top/right/bottom/left 都为0的简写,让伪元素撑满父元素的整个内容区。这个属性兼容性已经非常好,可以放心用。
3.6 关键帧动画:让钟摆像真的一样
这是整个项目最核心的部分。先直接给代码,再逐行拆解:
css复制@keyframes swing {
0% { transform: rotate(-30deg); }
50% { transform: rotate(30deg); }
100% { transform: rotate(-30deg); }
}
就这三行,没了。但千万不要小看这三行,它里面藏了三个关键知识点:
第一个知识点:为什么是30度?
30度是我反复试出来的。摆幅太小(比如10度),动画看起来像在“抖”而不是在“摆”;摆幅太大(比如50度以上),视觉上会显得夸张、不稳。30度是一个视觉和心理上都比较舒服的角度,刚好在“优雅”和“存在感”之间找到平衡。你可以改成45度感受一下,会发现整个动画的气质完全不同。
第二个知识点:为什么100%是回到-30度,而不是0度?
这是新手最常犯错的地方。很多人会写:
css复制@keyframes swing {
0% { transform: rotate(-30deg); }
50% { transform: rotate(30deg); }
100% { transform: rotate(0deg); }
}
这样写的问题在于:动画结束时的状态是0度(钟摆垂直静止),但动画循环时下一轮的开始状态是-30度,中间会有一条“跳变”的动画,摆锤会在完成一次摆动后突然闪回左边。而正确的写法是让 100% 的状态和 0% 的状态一致,这样动画在无限循环时首尾无缝衔接,看起来像一直连续在摆。
第三个知识点:为什么用 transform: rotate() 而不是 left/top 来移动?
上面说了性能原因,这里补充一个更直觉的理解:如果用 left 来移动钟摆,你还需要同步计算摆锤的弧线轨迹;而 rotate 天然就是绕 transform-origin 画弧线,物理规律本身替你算好了。你要做的只是“定义一个旋转角度”,剩下的事浏览器全包了。
3.7 动画参数:时长、缓动与循环
为了让钟摆“有灵魂”,动画属性要这样配:
css复制animation: swing 2s ease-in-out infinite;
逐个拆解:
2s:一个完整周期(左-右-左)用时2秒。这个值决定了钟摆的“气质”。1秒太快,显得急躁;3秒太慢,显得拖沓;2秒刚好,接近真实座钟的频率。ease-in-out:缓动函数,意思是“两头慢、中间快”。这恰恰对应钟摆的真实物理过程——摆到最高点时速度为零,然后加速下落,经过最低点时速度最大,再减速上升。如果你用linear,整个摆动会像节拍器一样机械地匀速往复,缺失了接近真实物理的“呼吸感”。infinite:无限循环播放。
这里有一个进阶话题:ease-in-out 虽然已经很接近真实效果,但严格来说,真实钟摆在最低点附近的速度变化比 ease-in-out 更快。如果你想追求更真实的物理感,可以用自定义贝塞尔曲线:
css复制animation: swing 2s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
或者更精细一点,把关键帧拆成四段,分别模拟减速-加速-减速-加速的过程:
css复制@keyframes swing {
0% { transform: rotate(-30deg) }
25% { transform: rotate(-8deg) }
50% { transform: rotate(30deg) }
75% { transform: rotate(8deg) }
100% { transform: rotate(-30deg) }
}
但实测下来,ease-in-out 对大多数场景已经完全够用了。我不会建议你在一个入门项目里过度优化到物理引擎级别,那是过犹不及。
3.8 完整代码整合:复制就能跑
把所有代码拼在一起,就是下面这一整个文件。直接复制到一个 .html 文件里,浏览器打开就能看到效果。
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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #1a1a2e;
font-family: system-ui, sans-serif;
}
.scene {
position: relative;
width: 300px;
height: 400px;
overflow: hidden;
border-bottom: 3px solid #e0c068;
}
.scene::before {
content: "";
position: absolute;
top: 40px;
left: 50%;
transform: translateX(-50%);
width: 80px;
height: 8px;
background: #e0c068;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
}
.clock-pendulum {
position: absolute;
top: 60px;
left: 50%;
width: 4px;
height: 260px;
margin-left: -2px;
transform-origin: 50% 0%;
animation: swing 2s ease-in-out infinite;
}
.pendulum-arm {
position: absolute;
top: 0;
left: 50%;
width: 4px;
height: 220px;
margin-left: -2px;
background: linear-gradient(to bottom, #e0c068, #b8943f);
border-radius: 2px;
}
.pendulum-bob {
position: absolute;
bottom: 0;
left: 50%;
width: 44px;
height: 44px;
margin-left: -22px;
}
.pendulum-bob::before {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle at 35% 30%, #f5d76e, #c9a035 60%, #7a5c1a);
border-radius: 50%;
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.5),
inset 0 -4px 6px rgba(0, 0, 0, 0.2);
}
.pendulum-bob::after {
content: "";
position: absolute;
left: 50%;
top: 0;
width: 3px;
height: 100%;
transform: translateX(-50%);
background: linear-gradient(to bottom, #e0c068, #b8943f);
}
@keyframes swing {
0% { transform: rotate(-30deg); }
50% { transform: rotate(30deg); }
100% { transform: rotate(-30deg); }
}
</style>
</head>
<body>
<div class="scene">
<div class="clock-pendulum">
<div class="pendulum-arm"></div>
<div class="pendulum-bob"></div>
</div>
</div>
</body>
</html>
你把这个文件保存后双击打开,页面中央就会有一个金色钟摆在持续摆动。如果发现没动,检查一下是不是把 @keyframes 写在了 animation 属性后面——CSS里 animation 引用的关键帧名字,跟 @keyframes 的定义位置没有先后要求,但拼写必须完全一致,尤其是大小写。
4. 避坑指南与常见问题实录
这一节是全文含金量最高的部分。以下问题是初学者最容易踩的坑,也是我当初一个个试出来的。
4.1 摆锤看起来在抖动、左右乱晃
现象:动画确实在动,但摆锤在运动过程中有肉眼可见的颤动,或者轨迹明显不是一个平滑的圆弧。
原因排查:这是 transform-origin 设置不对的典型症状。如果中心点设置到了容器中心(默认值),那钟摆会绕着自己的几何中心旋转,看起来就像整个结构在“翻身”而不是在“摆动”。如果你同时给多个元素加了旋转动画,还可能产生叠加干扰。
正确做法:确认 transform-origin: 50% 0% 写在 .clock-pendulum 上,而不是写在 .pendulum-arm 或 .pendulum-bob 上。只有最外层的摆动容器需要旋转中心点,内部子元素不需要。
4.2 动画结束时钟摆“闪回”到起点
现象:动画播放完一个周期后,钟摆会突然跳回初始角度,然后再从头开始摆,中间有肉眼可见的断裂感。
原因:关键帧的终点状态和起点状态不一致。如果你写了 0% { rotate(-30deg) } 50% { rotate(30deg) } 100% { rotate(0deg) },动画播完最后一帧会突然从0度跳到下一轮的-30度,这个跳变就是“闪回”。
正确做法:确保 100% 和 0% 的旋转角度一致。或者,更偷懒的方式是使用 animation-direction: alternate:
css复制animation: swing 2s ease-in-out infinite alternate;
加了 alternate 后,动画会在 0% 和 50% 两个关键帧之间来回交替播放,自动反转方向,不需要写100%那一帧。这是很多老手惯用的写法,代码更简洁。
4.3 ease-in-out 用在错误的位置
现象:动画在来回摆动时,最低点(中间位置)反而感觉速度慢了,跟真实钟摆相反。
原因:animation-timing-function 默认作用于整个关键帧周期。也就是说,ease-in-out 会让“从一个关键帧到下一个关键帧”的过渡都遵循“慢-快-慢”的节奏。在钟摆场景下,从 -30度到30度是半个周期,这段时间里 ease-in-out 会让它经历“慢(左顶点出发)→快(经过中间)→慢(到达右顶点)”,这其实恰好是对的。真正会出问题的是,如果你把它写在了单个关键帧上(50% { transform: rotate(30deg); animation-timing-function: ease-in-out; }),控制的是“到达这个关键帧之前的过渡”,一不留神就会搞反。
正确做法:在 animation 简写属性里统一设置 ease-in-out,不要在每个关键帧里单独设置。
4.4 页面上出现了横向滚动条
现象:动画播放时,页面底部或侧面出现滚动条,整个页面可以左右拖动。
原因:钟摆摆动到最大角度时,摆锤的宽度超出了视口边界。虽然摆锤本身的 overflow 没有溢出,但 body 的可视区域被撑大了。
正确做法:给包裹场景的父容器加 overflow: hidden,或者给 body 加 overflow-x: hidden。我推荐前者,因为更精准、副作用更少。同时确认 .scene 的宽度和高度足够容纳钟摆的最大摆幅。300x400这个尺寸配合30度摆幅是绝对够用的,如果改了更大的角度,记得同步调整场景尺寸。
4.5 背景色渐变导致挂杆看不见
现象:摆杆看起来若隐若现,或者从某些角度看颜色跟背景融为一体。
原因:摆杆宽度只有4px,如果背景颜色和摆杆颜色过于接近,视觉上会被“吃掉”。另外,如果给 body 设置了偏深的背景色,而摆杆是深金色,在某些屏幕上对比度不够。
正确做法:摆杆颜色用亮一点的金色渐变,并且可以加一个极淡的投影:
css复制.pendulum-arm {
box-shadow: 0 0 2px rgba(0,0,0,0.3);
}
4.6 动画不动?先检查这三处
如果打开页面后钟摆纹丝不动,优先检查:
- CSS是否生效:浏览器F12打开开发者工具,看
animation属性是否被划掉了。 @keyframes名称拼写:swing是不是写成了sawing或sing。transform是否被覆盖:如果后续你不小心又给.clock-pendulum写了transform: translateX(...),它会覆盖关键帧里的transform: rotate(...)。这是CSS动画最隐蔽的坑——同一元素的transform不能同时被两条规则控制。
关于第3点多说一句:如果你需要给钟摆额外做位移,不要直接写 transform: translateX(...),而是应该把位移和旋转合并到同一个 transform 里,比如 transform: translateX(20px) rotate(-30deg);。这在复杂动效里是非常高频的踩坑点。
4.7 真机预览时摆动不流畅
现象:在电脑浏览器上没问题,但用手机打开时摆动掉帧、卡顿。
原因:手机上如果触发了 box-shadow 大面积变化、border-radius 和 filter 同时计算的动画,GPU负担会增加。另外,如果页面没有设置 viewport meta 标签,手机浏览器会按980px宽度渲染页面,缩放后动效自然不流畅。
正确做法:确保有 <meta name="viewport" content="width=device-width, initial-scale=1.0">,并且让 animation 只作用于 transform 和 opacity 这两个属性,不要对 left、top、width、box-shadow 做动画。我们的钟摆恰好只用到了 transform,已经是性能最优解了。
4.8 关键帧90%到100%之间的“回弹”问题
现象:动画看起来像是先向左摆、再弹回来、然后才开始向右摆,节奏不对。
原因:如果写了3个以上关键帧(比如0%、25%、50%、75%、100%),并且某个中间关键帧的角度设置错了,会在那个节点产生意外的反向运动。
正确做法:新手阶段只保留 0% 和 50% 两个关键帧,配合 alternate 实现左右往复。等你能完全理解关键帧之间的插值逻辑,再尝试三段式缓动、自定义贝塞尔曲线这些更高级的玩法。
5. 进阶扩展与变体思路
钟摆做完了,别急着收工。花几分钟试一下这几个变形,你会对CSS动画产生新的理解。
5.1 从摆动到摇晃:不止是钟摆,还能做树枝、吊灯和风铃
把摆幅从30度改成15度,把动画时长从2s改成3s,再用 ease-in-out 配合更轻的质感,这个结构立刻变成一个被风吹动、轻微摇晃的吊灯。你只需要把摆锤换成灯的造型:
css复制.pendulum-bob::before {
border-radius: 4px;
background: radial-gradient(circle at 50% 20%, #fff8e1, #ffe082, #ffb300);
}
四角圆润的灯罩形状就出来了。
5.2 多摆联动:场景感瞬间拉满
把 .clock-pendulum 复制三份,分别向外侧错开位置,设置不同的动画延迟:
css复制.pendulum:nth-child(2) {
animation-delay: -0.5s;
}
.pendulum:nth-child(3) {
animation-delay: -1s;
}
三个钟摆以不同的相位来回晃动,会产生一种复杂的、有机的节奏感,很像风吹过树林时树枝的不同步晃动。这个效果在大型品牌官网的加载页上经常能看到。
注意:animation-delay 用负数可以让动画从中间的某个位置开始播放,这样三个钟摆在页面加载时就不是从同一起点出发,而是各自处于不同的摆动相位。
5.3 性能优化:让动画更丝滑
如果钟摆动画要放在一个元素很多的页面上,建议加上 will-change 提前告知浏览器哪个元素会频繁变化:
css复制.clock-pendulum {
will-change: transform;
}
这是一个“性能提示”,告诉浏览器:这个元素之后会频繁变换,请提前做好渲染优化。但是不要滥用——每个元素都加 will-change 反而会消耗大量内存。只对真正需要动画的元素加即可。
5.4 深色背景适配:让钟摆在暗色主题下更高级
当前代码里的 #1a1a2e 是深蓝黑,配金色不错。如果你想走极简风,改成纯黑背景,配白色金属质感:
css复制body {
background: #0d0d0d;
}
.pendulum-arm {
background: linear-gradient(to bottom, #f0f0f0, #c0c0c0);
}
.pendulum-bob::before {
background: radial-gradient(circle at 35% 30%, #ffffff, #a0a0a0 60%, #505050);
}
一套全新的质感就出来了。
6. 个人实操心得与最后的小建议
从写下第一行HTML到钟摆流畅地晃动起来,我大概反复调整了十几版。最深的体会有三条:
第一条,CSS动画调试的核心是“分而治之”。先不写动画,把静态结构的位置调准确——悬挂点、摆杆、摆锤三者严格对齐;然后再加 transform-origin;最后才写 @keyframes。每加一层只验证一件事,出错时就能快速定位。千万不要一上来就全写在一起,出了问题你根本不知道是哪里错了。
第二条,角度和时长一定要亲自调一遍。30度、2秒是我给出的推荐值,但它未必是你审美里的最佳值。试着把角度改成20度、把时长改成1.5秒,你会立刻发现“同一个结构的动画,气质完全不同”。这种手感不是看书能学来的,必须自己动手扭参数。
第三条,纯CSS动画有它不可替代的一面。很多人觉得动画就得JavaScript来写,但做了这个项目你就会发现,CSS里 transform + transform-origin + @keyframes 三个属性组合起来,已经能实现大量复杂物理效果。而且它的性能优势和代码简洁度,是JS方案很难比的。以后做前端面试题、做个人项目、做产品动效,这套思路都能复用上。
最后再分享一个小技巧。如果你想让钟摆摆到最高点时有一瞬间的“停顿感”,也就是接近真实钟摆那种在顶端悬停的感觉,可以给关键帧加一行:
css复制@keyframes swing {
0%, 15% { transform: rotate(-30deg); }
50% { transform: rotate(30deg); }
85%, 100% { transform: rotate(-30deg); }
}
0%, 15% 表示在动画开头15%的时间里,角度都保持-30度不动;85%, 100% 同理,在结束前的15%时间里保持-30度。这样钟摆到达顶点后会短暂“驻留”,然后才折返,摆动节奏感更强,也更接近真实物理里“速度为零再反向”的感觉。这是很多人不知道的小细节,试完你会回来感谢我的。
