纯CSS3齿轮咬合滚动动画:齿比计算与animation参数详解
2026/9/15 22:42:18 网站建设 项目流程

简介:纯CSS3实现的齿轮咬合滚动动画源码,是一份极简的前端交互示例,面向对CSS动画与视觉实现感兴趣的学习者,展示了仅依靠样式表完成齿轮精确咬合与持续滚动的完整思路。包体仅1个HTML文件,大小约1KB,没有冗余依赖,可直接在浏览器中打开,便于逐行研读与实时修改参数。目前已有79人学习下载,适合作为CSS3进阶的微型案例。实现中运用了@keyframes动画关键帧、transform的rotate旋转、transition平滑过渡、相对单位与定位来保证齿轮在不同视口下的咬合节奏;同时借助伪元素与HSLA色值补充齿轮细节,并可能涉及媒体查询与will-change等性能优化手段,为读者提供了多个可拆解的知识点。开发者可以动手调整齿数、转速或加入暂停交互,将这套齿轮模型迁移至加载动画、仪表盘或机械感UI中,体会纯CSS实现动态视觉的轻量而可控的工作方式。

1. 纯CSS3齿轮咬合滚动动画:不写JS,先把齿比算明白

齿轮动画只要一涉及「咬合」,就比单独旋转难一个量级:两个齿数不同的轮子,转一圈的时间、方向、起始角度必须严格对齐,差半度都会让人一眼看出「打齿」。很多人第一反应是上 Canvas 或 SVG,但纯 CSS3 动画天生够用——animation本身就支持linear无限循环、reverse反向执行、负delay调整相位,这三个能力正好是齿轮啮合的全部数学基础。真正拦路的是两件事:齿形怎么用CSS画出来,以及把齿数比换算成animation-duration。这篇顺着「先把机械规则讲清,再落到可运行代码」的顺序,给出一套不用一行 JavaScript 的实现方案,最后讲怎么验证咬合、怎么把项目整理成可直接分发运行的源码压缩包。适合要写加载页、装饰性 H5 动效,或者想把animation节奏控制彻底吃透的前端开发者。

2. 咬合前的几何课:齿数、角速度与CSS动画参数一一对应

2.1 齿轮咬合的三条硬规则

把两个真实齿轮放在一起观察,能得到三条运动学约束,它们直接决定动画参数怎么写。

第一条,外啮合的两个齿轮转向相反,一个顺时针,另一个必然是逆时针。第二条,转速与齿数成反比:20 齿的齿轮转 1 圈,10 齿的齿轮在同一时间里已经转了 2 圈。第三条,啮合点瞬时线速度相同,两轮在接触点的切向速度相等,所以小齿轮角速度大,但齿尖走过的弧长一样。

这三条规则落到 CSS 上分别是:转向由animation-direction: reverse控制;转速比由animation-duration的比值控制;初始咬合位置由animation-delay的负值来对齐相位。只要这三个参数写对,剩下的纯视觉效果只是锦上添花。机械里还有模数、压力角等概念,动画只保留「齿数比决定转速比、直径与齿数成正比」这两条就够用,不必做全套齿轮设计。

2.2 把运动规则翻译成 animation 参数

CSS 的animation简写属性背后有多个子属性,写齿轮动画时最常接触的就是下面这几个:

机械概念CSS 子属性取值说明
转一圈的周期animation-duration齿数越多,duration越长,和角速度成反比
转向animation-directionreverse表示从关键帧尾部往回执行,等效反方向旋转
初始相位animation-delay负值表示动画已经播了一段时间,直接从那一帧开始
永续旋转animation-iteration-countinfinite让齿轮不停转
是否匀速animation-timing-functionlinear保证角速度恒定,缺失会忽快忽慢
播放启停animation-play-statepaused用于调试咬合位

转速比换算公式也很直接。设大齿轮齿数为 z₁,小齿轮为 z₂,大齿轮转一圈用时 T₁,则小齿轮的周期:

T₂ = T₁ × z₂ / z₁

例如大齿轮 30 齿、小齿轮 15 齿,T₁ 取 6 秒时,T₂ = 6 × 15 / 30 = 3 秒。小齿轮齿数越少,周期越短,转速越快,和物理直觉一致。方向则直接取反。这个公式是整个齿轮动画里唯一的硬计算。

2.3 为什么不用 JS 或 SVG 轮子

常见替代方案是requestAnimationFrame驱动transform,或者用 SVG 的animateTransform,它们都能实现旋转,但在持续滚动场景各有别扭处。JS 方案每帧回调,主线程一旦忙碌,动画时间轴就抖动,在低端手机上尤其明显;SVG 的animateTransform不是不能做,但它运行在 SVG 坐标系里,要和 HTML 文本、布局混排时反而绕。

纯 CSS3 动画在浏览器里由合成器线程处理,只要动画属性限定在transform/opacity,主线程再忙也不太影响帧率。这正是「纯CSS」在机械装饰动效里仍然有存在感的原因,它是能量损耗最小的旋转通道。开发者只需要算对durationdelay,浏览器负责在独立图层里转圈,这是 SVG 和 JS 方案都不容易拿到的收益。

3. 用CSS3徒手画齿轮,搭出第一组咬合体

3.1 齿形绘制方案对比

画齿形有三条路。一是内联 SVG 画路径再用 CSS 旋转,最精细但引入了额外 DOM;二是用多个矩形伪元素拼齿,代码重复且定位繁琐;三是用repeating-conic-gradient,一个background属性就画出齿顶与齿槽的周期图案,没有任何额外节点,背景跟随元素transform一起旋转,坐标系天然统一。

关键参数是「一个齿占多少度」。齿轮有 z 个齿,每齿在圆周上占360 / z度,这段角度再一分为二,一半是齿顶、一半是齿槽。以 16 齿为例,每齿占 22.5 度,齿顶和齿槽各 11.25 度,写法如下:

.gear { width: 120px; height: 120px; border-radius: 50%; background: repeating-conic-gradient( #2d3436 0deg 11.25deg, #dfe6e9 11.25deg 22.5deg ); }

这段渐变从正右方向开始,深色段是齿顶,浅色段是齿槽,每 22.5 度完成一次齿距循环。repeating-conic-gradient会把颜色片段沿圆周无限重复,所以不管 14 齿还是 32 齿,改度数即可,不需要新增 DOM 节点。注意齿数与角度的整除关系,如果 360 不能被齿数整除,渐变会在起点处断裂,形成一条可见接缝。

接着用伪元素挖空中心。::before覆盖齿根圆,让它露出和页面一样的底色,视觉上齿与齿之间就有了空隙;::after画轴孔:

.gear { position: relative; /* 上面的尺寸和背景保持不变 */ } .gear::before { content: ""; position: absolute; inset: 18%; border-radius: 50%; background: #fafafa; /* 必须与页面背景色一致 */ } .gear::after { content: ""; position: absolute; inset: 36%; border-radius: 50%; background: #2d3436; }

inset的百分比是相对元素尺寸的,18%表示内圆半径约为外圆的 82%,这个比例决定齿根的深度。百分比越大,齿越短。齿顶是扇形直角齿,和真正的渐开线齿形有差别,但动画表演里没人会停下来量压力角,视觉周期正确就达标。

3.2 同齿数齿轮:最小咬合 DEMO

先放两个 16 齿齿轮,直径都是 120px。由于齿数相同、直径相同,转速也相同,只需要保证方向相反。HTML 结构是两个兄弟节点包在一个定位容器里:

<div class="rig same-size"> <div class="gear g1"></div> <div class="gear g2"></div> </div>
.rig { position: relative; width: 240px; height: 140px; background: #fafafa; } .g1 { position: absolute; left: 0; top: 10px; } .g2 { position: absolute; left: 114px; top: 10px; } .g1 { animation: spin 6s linear infinite; } .g2 { animation: spin 6s linear infinite reverse; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

两个齿轮的圆心距设为 114px,而元素直径是 120px,相当于留了 6px 的齿高重叠量,齿尖恰好能插进对方的齿槽。这个值需要在浏览器里微调,每次增减 2px 观察齿间是否挤压。g2reverse后,视觉上就是从左往右看时两个轮子一个顺时针、一个逆时针,啮合关系成立。

不要试图让两个同齿数齿轮用不同的duration,那只会让它们越转越错位。同齿数意味着周期必须一致,唯一的自由度是初始相位,由animation-delay微调。

3.3 不同齿数:转速比与圆心距修正

真正的「咬合」感往往来自大小齿轮搭配。把 3.1 的齿轮改成 32 齿大轮和 16 齿小轮,大轮直径 160px,小轮 80px。大轮周期 6 秒,小轮按公式 T₂ = T₁ × z₂ / z₁,也就是 6 × 16 / 32 = 3 秒,方向取reverse

.g-big { width: 160px; height: 160px; background: repeating-conic-gradient( #2d3436 0deg 5.625deg, #dfe6e9 5.625deg 11.25deg ); position: absolute; left: 0; top: 20px; animation: spin 6s linear infinite; } .g-small { width: 80px; height: 80px; background: repeating-conic-gradient( #2d3436 0deg 11.25deg, #dfe6e9 11.25deg 22.5deg ); position: absolute; left: 114px; top: 60px; animation: spin 3s linear infinite reverse; animation-delay: -0.35s; }

圆心距不再是两个直径相加的一半。大轮半径 80px,小轮 40px,理想中心距 120px,但齿高重叠要占掉空间,这里取 114px 左右,让齿尖互相嵌入。animation-delay: -0.35s的负值表示小轮跳过前 0.35 秒的旋转量,从某个已转过的角度开始播放,作用就是对齐两轮第一帧的咬合相位。

这个 0.35 秒怎么来?先把动画暂停,用浏览器开发者工具手动给元素加transform: rotate(...),调到两齿刚好贴合的位置,记下角度差,再用delay = -T × 角度差 / 360换算。后面第五章会给出不用手动算数的验证技巧。

4. 咬合 + 滚动:让齿轮组在画面上滚起来

4.1 两种「滚动」别混为一谈

标题里的「滚动动画」其实是两层意思:一层是齿轮自身持续旋转,前面已经实现;另一层是整个齿轮组作为刚体在视口里平移,比如加载页里一组齿轮从右侧滚进画面,或者齿轮组做成页脚的装饰履带。

两层滚动要放在不同的元素上。外层容器负责translateX整体位移,内层每个齿轮负责自己的rotate。如果把位移和旋转写进同一个元素的transform,后者会覆盖前者,动画直接失效。这是「滚动 + 咬合」组合时最常见的翻车点。

4.2 齿轮组进场:CSS3动画延迟与末态保持

给齿轮加进场动画时,会遇到 CSS3 动画两个典型问题:延迟期间元素是显示还是隐藏,以及动画结束后是否保持最后一帧。这两件事由animation-fill-mode控制。多个动画用逗号分隔,各自的delay也按逗号对应:

.gear-a { animation: spin 6s linear infinite, enter 1.2s ease-out both; } .gear-b { animation: spin 3s linear infinite reverse, enter 1.2s ease-out both; animation-delay: 0s, 0.4s; } @keyframes enter { from { opacity: 0; transform: scale(0.6); } to { opacity: 1; transform: scale(1); } }

both的作用是让enter动画在延迟期间先应用from状态(齿轮透明且缩小),结束后停留在to状态。如果漏掉它,延迟期间元素以默认状态展示,视觉上会闪一下;动画结束后又跳回opacity: 1的默认值,过渡就断了。.gear-b0s, 0.4s是分别给spinenter设延迟,进场比.gear-a晚 0.4 秒,形成一前一后介入的节奏。

注意进场动画的transform: scale(...)和自转的transform: rotate(...)属于同一个属性,如果写在同一个元素上会互相覆盖。上面这段代码里它们确实都作用在.gear-a上,但一个在spin里、一个在enter里,同一时刻只有同名列的动画在写transformspinenter同时激活时会冲突。实际要拆开:把enter放在外层包装元素上,spin放在齿轮元素上,或者让enter只动画opacity。先用包装元素方案:

<div class="rig"> <div class="gear-a-wrap"><div class="gear-a"></div></div> <div class="gear-b-wrap"><div class="gear-b"></div></div> </div>

.gear-a-wrapenter.gear-aspin。两个动画各管一个元素,transform不再打架。这是同时跑位移、旋转、缩放进场时的通用分层原则。

4.3 滚动循环:执行次数、逆向播放与无缝衔接

齿轮组要做成背景履带,通常选两种节奏。一种是无缝单向循环,一种是在页面里来回滚动的往复效果。

无缝单向循环需要内容复制两份,容器内部用过长的translateX(-50%)制造接缝。HTML 里放两个完全相同的齿轮组副本,卷轴容器宽度设为两倍,动画从 0 位移到 -50% 时,第二份内容顶到第一份的位置,视觉上就接续上了:

.belt { display: flex; width: max-content; animation: slide 12s linear infinite; } @keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }

这里-50%相对的是.belt自身宽度。因为两副本等宽,移动自身宽度的一半正好完成一次循环。animation-direction在这个场景不需要写,默认normal就一直往一个方向滚。往复效果则在动画上多加一个alternate

.belt-bounce { animation: slide 12s linear infinite alternate; }

alternate每次循环结束后自动逆向执行,配合infinite就成了来回滚。CSS3 动画的执行次数和逆向播放组合起来,能覆盖大多数滚动节奏:infinite + normal永续单向,infinite + alternate永续往复,1 + normal播一次停住。需要「播一次停住且停留在终点」时,记得在动画末尾加both,只写normal + infinite停不下来,只写forwards又会把延迟阶段的状态弄丢。

5. 验证咬合同步,把项目整理成可直接跑的源码包

5.1 用 CSS 修车闸:一个 checkbox 暂停咬合

咬合验证最直接的办法是让动画暂停,看齿尖是否停在齿槽正中央。虽然实现里没有 JavaScript,但验证可以用纯 CSS 的 checkbox hack:一个被checked的复选框配合通用兄弟选择器,控制后面所有动画的播放状态。把下面这段放进上面任意一节的结构里:

<input type="checkbox" id="brake" class="brake-input" checked> <label for="brake">咬死齿轮</label> <div class="belt"> <div class="rig"> <div class="gear-a-wrap"><div class="gear-a"></div></div> <div class="gear-b-wrap"><div class="gear-b"></div></div> </div> <div class="rig"> <div class="gear-a-wrap"><div class="gear-a"></div></div> <div class="gear-b-wrap"><div class="gear-b"></div></div> </div> </div>
.brake-input:checked ~ .belt * { animation-play-state: paused; }

复选框的checked属性能在刷新后依然保持状态,默认勾选,打开页面就直接是静止的咬合状态。取消勾选,齿轮组开始滚动。animation-play-state: paused不重置动画进度,只是把当前帧冻结,所以检查完松开,动画从刚才的位置继续,不会跳帧。

5.2 咬合不同步的三种症状与快速修法

症状原因修法
齿尖互相穿透,像打架圆心距太小,或animation-delay相位没对齐调大两轮left间距;用 5.1 暂停法看齿槽间隙,调负delay
转速忽快忽慢,失去机械感animation-timing-function不是linear每个动画显式写linear,不要依赖默认ease
小齿轮转速明显不对duration比值算错T₂ = T₁ × z₂ / z₁反推,齿数比反了是最常见的
进场前元素闪烁animation-fill-mode缺失进场动画补both,让末态持续生效

5.3 把源码打包成 zip:目录结构与交付细节

一个纯 CSS 齿轮动画项目不需要构建工具,推荐按这种最简目录组织:

gear-bite-roll/ ├── index.html ├── css/ │ └── style.css └── assets/ └── (可选背景图,不使用则留空)

index.html里用<link rel="stylesheet" href="css/style.css">引入样式,所有齿轮、动画、checkbox 调试开关全在 HTML 和 CSS 内完成。打包成 zip 前把调试用的label:checked规则注释掉,或者保留它们并在交付说明里写一句「勾选复选框可暂停动画检查咬合」。因为没有外部字体、图片和接口依赖,解压后直接把index.html拖进 Chrome、Edge 或 Firefox 就能运行,也不需要起本地服务器。最后提醒一点:zip 内的文件名全部用英文小写,避免个别解压工具对中文文件名的编码处理不一致,导致 HTML 引用路径失效。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询