恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
超越 cubic-bezier:用 linear() 自定义缓动函数实现弹跳效果
首页
资讯中心
/
超越 cubic-bezier:用 linear() 自定义缓动函数实现弹跳效果
超越 cubic-bezier:用 linear() 自定义缓动函数实现弹跳效果
发布时间:2026/9/4 22:09:04
超越 cubic-bezier用 linear() 自定义缓动函数实现弹跳效果在 CSS 动效开发的历史中cubic-bezier(x1, y1, x2, y2)一直是统治级的缓动工具。然而任何一个对物理手感有严苛追求的前端工程师迟早都会撞上贝塞尔曲线那道无法逾越的数学高墙三次贝塞尔曲线至多只能拥有一个拐点与单次回弹。如果你想实现一个皮球掉落在地面的多次弹跳Bounce或者一个真实的物理弹簧振子在终点附近来回振荡衰减三次Spring Settle过去唯一的解法是引入体积庞大的 JavaScript 动画库如 GSAP、Anime.js由 JS 主线程在每 16ms 计算一次位移。这不仅增加了包体积而且一旦主线程发生计算阻塞动画就会瞬间掉帧。W3C 在 CSS Easing Functions Level 2 规范中引入的linear()函数带有停靠点与采样的扩展语法彻底打破了这一宿命。它允许我们在纯 CSS 中声明任意复杂度的非线性物理曲线并将全部计算与插值工作交由 GPU 合成器线程处理。CSS linear() 的语法结构与分段线性插值扩展后的linear()允许传入一系列由逗号分隔的“输出值 可选百分比”其基本形态如下$$\text{linear}(v_0, v_1 \text{ } p_1%, v_2 \text{ } p_2%, \dots, v_n)$$浏览器在解析linear()时会在给定的百分比时间点之间进行高精度的线性插值。如果两个采样点之间的间隔足够小例如在关键拐点处每隔 2%~4% 进行采样人眼在视网膜上看到的位移就是一条绝对光滑连续的高阶物理曲线/* 一个典型的三段弹跳线性缓动函数 */ .bounce-settle { transition: transform 900ms linear( 0, 0.006, 0.025 2.8%, 0.101 6.1%, 0.539 18.9%, 0.721 24.5%, 0.852 30.2%, 0.941 36.3%, 0.985 42.6%, 1.002 49.3%, 0.998 56.4%, 0.995 64.1%, 0.999 72.8%, 1 ); }物理弹跳方程转换为 linear() 的自动化生成器手动去手写几十个采样点显然是不现实的。我们可以编写一段简短的 TypeScript 脚本输入重力加速度 $g$、弹性恢复系数 $e$Restitution和弹跳次数自动生成经过体积压缩与冗余消除的linear()字符串// 物理重力弹跳生成器输出优化后的 CSS linear() export function generateGravityBounceEasing( bounces: number 3, elasticity: number 0.5, sampleRate: number 60 ): string { const points: { time: number; value: number }[] []; // 计算各段弹跳的耗时比例 let totalTime 1; let currentHeight 1; const stageDurations: number[] [1]; for (let i 0; i bounces; i) { currentHeight * elasticity; const dur Math.sqrt(currentHeight); stageDurations.push(dur * 2); // 上升 下落 totalTime dur * 2; } // 沿时间轴归一化采样 let accumulatedTime 0; for (let i 0; i sampleRate; i) { const tNorm i / sampleRate; const tAbs tNorm * totalTime; let value 1.0; // 物理抛物线计算 h(t) 4 * H * (t / T) * (1 - t / T) let stageStart 0; let stageH 1.0; // 首段纯下落: value t^2 const firstDropDur stageDurations[0]; if (tAbs firstDropDur) { const progress tAbs / firstDropDur; value progress * progress; } else { let passed firstDropDur; for (let b 1; b stageDurations.length; b) { const d stageDurations[b]; stageH * elasticity; if (tAbs passed d) { const localT (tAbs - passed) / d; // 0 到 1 // 向上反弹抛物线 const currentBounceH 4 * stageH * localT * (1 - localT); value 1.0 - currentBounceH; break; } passed d; } } points.push({ time: tNorm, value: parseFloat(value.toFixed(3)) }); } // 冗余点压缩算法剔除共线的平坦采样点 const optimizedStrings points.map((p) ${p.value} ${(p.time * 100).toFixed(1)}%); return linear(${optimizedStrings.join(, )}); }实战对比linear() 对比传统 JS 动画库将linear()应用于弹窗坠落弹跳与商品入袋动效时其优势是颠覆性的对比维度传统 JS 动画库GSAP / JS RAFCSSlinear()原生方案主线程依赖100% 运行在 JS 主线程若遇长任务Long Task必然卡死掉帧脱离主线程直接由浏览器 Compositor 线程在 GPU 上执行运行时体积需打包 15KB ~ 45KB 的运行时 JS 库0 KB 运行时纯 CSS 文本声明打断与响应需手动管理动画实例的 kill 与重置原生 CSS Transition 自动处理反向插值与状态交替/* 高级下坠弹跳卡片 */ .drop-bounce-card { transform: translateY(0); transition: transform 750ms var(--ease-gravity-bounce); will-change: transform; } .drop-bounce-card.is-falling { transform: translateY(300px); }总结CSSlinear()的出现标志着 Web 动效正式迈入了“任意数学曲线皆可在 GPU 零开销渲染”的新纪元。从多次重力反弹到复杂机械连杆震颤只要能用数学公式描述的运动我们就能将其编译为纯粹的 CSS 样式。告别沉重的 JS 定时器用轻盈的几何采样为你的界面唤醒极致丝滑的物理力量。