Jelly UI 浪潮:当软体物理交互重塑前端设计语言
过去十年,前端设计语言在"扁平化—拟物化—新拟态"的循环中不断摇摆,而 2024 年前后悄然兴起的一股 Jelly UI(软体弹性 UI)风潮,让设计师重新将目光投向物理直觉。这一次,设计师不只是为了好看,而是为了让每一次点击、滑动、状态切换都符合用户对"物质世界"的心智模型。更值得关注的是,这场复兴不再依赖庞大的 JavaScript 库,而是建立在 CSS 原生能力、Web Animations API、View Transitions 等基础之上的工程化实践。本文将围绕这一趋势,探讨软体物理交互如何复兴原生前端设计语言,以及如何以可工程化的方法承载无障碍体验。
一、Jelly UI 的核心特征:把"物质性"还给界面
Jelly UI 并非某家公司的专有体系,而是一种设计语言的取向:按钮被按下时像果冻一样凹陷、回弹,卡片拖拽时存在阻尼与轻微的形变,Modal 弹出时伴随弹簧曲线而非线性插值。这种设计有三个共同特征:
- 弹性反馈:交互响应具备 overshoot(过冲)与 settle(回稳)过程,使用户对触发结果有明确的因果感知。
- 质量与重力:不同元素根据视觉权重,呈现不同的"惯性"。底部 Tab 栏的弹动通常比顶部按钮更夸张,因为它被赋予更高的"物理地位"。
- 连续而非离散的过渡:界面状态不再硬切,而是通过位置、缩放、不透明度多通道插值,实现接近真实物体的运动连续性。
这种语言之所以在 2024 年再次引爆,核心推力来自 CSS 工作组对 motion primitives 的大幅扩展。当原生平台开始提供 spring-like 的能力,工程团队便有了脱离"黑盒动画库"的现实路径。
二、原生 CSS 设计语言的复兴
2.1 关键 API 概览
理解 Jelly UI 工程化,必须先盘点近年成为主流的原生特性:
| API | 能力 | 在 Jelly UI 中的角色 |
|---|---|---|
linear() easing | 多点贝塞尔 / 步进曲线 | 模拟弹性曲线,无需 JS |
View Transitions API | 同文档跨状态过渡 | 承载卡片变形、列表重排 |
@starting-style | 进入动画起点 | 元素 mount 时的"展开" |
scroll-driven animations | 滚动驱动动画 | 视差、头部回弹缩放 |
animation-composition | 组合多个动画 | 多通道插值的合成 |
Discrete transitions for display | 进出动画作用于 display | 折叠面板、菜单的弹性展示 |
2.2 一个可复用的弹性进入模式
传统上,我们要给 mount 元素做"弹入"效果,通常要借助 JS 钩子。在原生 CSS 体系下,可以这样写:
.card {
animation: jelly-in 600ms linear(0, 0.006, 0.025, 0.056, 0.113, 0.194, 0.301, ...);
animation-composition: add;
}
@keyframes jelly-in {
from { opacity: 0; transform: scale(0.6); }
to { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
.card { animation: none; }
}linear() 函数通过密集采样逼近真实弹簧曲线,在 GPU 合成层完成计算,性能开销远低于 JS 驱动的 spring loop。
三、软体物理的工程实现路径
3.1 何时选择 CSS,何时选择 JS?
落地策略可以归结为三条原则:
- 能 CSS 就不 JS:只要动画是确定性的(明确开始、明确结束、明确路径),优先用
linear()、@keyframes、View Transitions。 必须 JS 的场景:
- 用户实时拖拽时的橡皮筋效果(如 iOS 列表越界回弹);
- 多元素之间存在物理耦合(如手风琴折叠联动);
- 需要根据滚动速度、方向动态调参的场景。
- 框架内的轻量方案:React 生态下,Motion(原 Framer Motion)、@react-spring/web 已经把 spring 解算器与可访问性 hooks 融为一体,适合复杂编排。
3.2 弹簧方程的前端简化
现实工程不必为每一次动效计算完整 ODE,但工程师必须理解三件事,才能在团队中正确选择参数:
- 质量 m:决定响应惯性,按钮常用低质量,Modal 用中质量,拖拽放手回弹用高质量。
- 阻尼比 ζ:ζ < 1 欠阻尼(弹簧 overshoot),ζ = 1 临界阻尼(无 overshoot),ζ > 1 过阻尼(慢速缓动)。Jelly UI 偏好 ζ ≈ 0.6。
- 刚度 k:与 stiffness 同义,k 越大,响应越快、曲线越急促。
经验参数:Material Design 3 的 emphasized motion 推荐 stiffness: 380, damping: 30,Apple HIG 的 spring 默认 mass: 1, stiffness: 170, damping: 26。把这些预设写入设计 token,可在团队中保持一致的物理感。
四、无障碍体验的工程化方法论
软体物理交互最容易掉进的陷阱,就是动画过度化。一个合格的工程体系必须建立以下约束。
4.1 必须强制遵守的降级策略
prefers-reduced-motion: reduce:当用户开启降低动效偏好时,所有 spring 曲线降级为ease-out,时长压缩到 ≤ 100ms,或者直接以不透明度淡入替代位移。- 焦点不应跟随运动:键盘用户使用 Tab 浏览时,焦点元素的位置变化必须立即可读,不应依赖动画完成才可被屏幕阅读器无障碍树识别。
- 避免纯动效传达信息:颜色 + 图标 + 文本三重冗余依然必要,动效仅起到强化作用。
4.2 ARIA 与动效生命周期同步
当一个 Modal 以弹性曲线入场时,正确做法是:
- 在动画开始前即将
aria-hidden=true应用于背后内容; - 在动画的
animationend事件中,将焦点focus()到 Modal 内部首位可聚焦元素; - 提供显式的关闭手势,例如
Esc键绑定的非动画 fallback 路径。
这要求团队在动效组件库中,内置一组"无障碍契约",而不仅仅提供视觉 API。
五、性能预算与跨端一致性
5.1 性能基线
- 高频弹性动画必须只触发 transform 与 opacity;触发 layout、paint 的属性(如
width、top)会导致 60fps 失守。 - 在低端机(Android Go、入门级 iPhone)上将 spring 计算限制在主线程外,优先使用 CSS
linear()而非 JS RAF 循环。 will-change不应滥用,应当按需开启并在animationend后移除,避免长期占用合成层导致内存压力。
5.2 跨端交付的一致性策略
设计系统团队应当在以下三层落地约束:
- Token 层:定义
--motion-stiffness-emphasized: 380等命名空间语义,连接 iOS HIG、Android M3、自研规范; - 组件层:封装
<MotionButton>、<MotionSheet>等聚合组件,内部决定降级策略; - 观测层:接入 RUM(Real User Monitoring),统计
INP、CLS在动效开启前后的差异,作为体验验证依据。
六、结语:让原生回归,以工程承载美学
Jelly UI 浪潮并不只是视觉风格的轮回,它真正昭示的是前端设计语言向原生、向可工程化方向的回归。当 CSS 工作组持续输出 linear()、@starting-style、View Transitions 这类一等公民能力,前端工程师无需在交互丰富与可维护性之间二选一;相反,通过弹簧参数 token、动效组件契约、降级策略矩阵的体系化建设,我们可以同时交付出充满物质感与人人可用的产品。
未来的设计系统之争,大概率不在"用什么曲线",而在"怎样用最克制、最可访问、最接近原生的方式,让动效真正为理解服务"。这是 Jelly UI 复兴留给每一位前端工程师的命题,也是前端设计语言在新一轮周期的方向标。