【译】六个开发高手使用的 css 动画秘诀

makefile 复制代码
theme: juejin
highlight:juejin

原文🚀6 CSS Animation Secrets That Pro Developers Use

作者Blueprintblog

小声BB

本文在翻译过程中确保意思传达准确的前提下,会加入很多本人的个人解释和一些前置知识补充(使用引用块标注)

你可能见过那些流畅、专业的网站动画,让你不禁想问:"他们是怎么做到看起来这么轻松的?"虽然每个人都知道基本的CSS过渡效果,但还有一些奥秘,将业余动画与专业级动态设计区分开来。

为什么这些秘诀很重要

大多数开发者都知道使用 transition: all 0.3s ease 做过渡,但专业动画需要理解运用一些简单物理学、迎合浏览器的尿性以及揣摩用户心理。学会这些可以帮你:

  • 创建丝滑,自然的动画
  • 避免性能瓶颈,极致用户体验
  • 通过精致的交互建立信任,满足用户对现代应用的期望。
  • 掌握使用动画时间(timing)和动效(easing)的方法,让动画不突兀

尽量使用transform 写动效(保证60fps)

你要问我最大秘诀是啥?专业的动画只会对四个属性进行动画处理: transform, opacity, will-changefilter。其他的都会触发消耗巨大的重绘。

css 复制代码
/* ❌ 性能杀手 - 触发重排 */
.amateur-button {
  transition: width 0.3s, height 0.3s, margin 0.3s;
}
​
.amateur-button:hover {
  width: 200px;
  height: 60px;
  margin-top: 10px;
}
​
/* ✅ 丝滑 60fps - 只影响合成层 */
/* ✅ 丝滑 60fps -  只影响合成层 */
.pro-button {
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  will-change: transform;
}
​
.pro-button:hover {
  transform: scale(1.05) translateY(-2px);
}
​
/* 高级用法: 多个 transform 组合使用 */
.card {
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  transform-origin: center bottom;
}
​
.card:hover {
  transform: 
    translateY(-8px) 
    rotateX(5deg) 
    scalescale(1.02);
}

合成层是浏览器渲染系统中独立的一层,它可以被单独绘制并交给 GPU 进行处理。这意味着它可以:

妙在哪里: Transforms由 GPU 的合成器线程处理,完全绕过布局计算发生的主线程。这保证了即使在较旧的设备上也能实现流畅的性能。

使用场景:

  • 卡片悬停效果
  • 按钮交互
  • 模态窗口进入

在低性能设备上,也需要保证动画丝滑的场景。

真实的物理引擎🐶

忘记 ease-in-out。专业动画使用基于物理的缓动曲线,模仿现实世界的运动。

css 复制代码
/* ❌ ease-in-out 不自然 */
.basic-modal {
  transition: all 0.3s ease-in-out;
}
​
/* ✅ 真实物理引擎,丝滑 */
.pro-modal {
  transition: 
    transform 0.6s cubic-bezier(0.16, 1, 0.3, 1),
    opacity 0.4s cubic-bezier(0.4, 0, 1, 1);
}
​
/* 秘诀:不同属性对应不同的曲线 */
.notification {
  /* 快速淡入以立即可见 */
  opacity: 0;
  transform: translateX(100%) scale(0.8);
​
  transition: 
    opacity 0.2s cubic-bezier(0.4, 0, 1, 1),
    transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
​
.notification.show {
  opacity: 1;
  transform: translateX(0) scale(1);
}
​
/* 小贴士:为特定交互自定义缓动 */
:root {
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-in-out-circ: cubic-bezier(0.85, 0, 0.15, 1);
}
​
.button {
  transition: transform 0.2s var(--ease-out-back);
}
​
.button:active {
  transform: scale(0.95);
}
​

妙在哪里: 这些曲线模拟真实物理------物体开始时加速,略微超过,然后稳定。你的大脑认为这是自然运动。

使用场景:

  • 按钮点击
  • 弹窗动画
  • 提示消息滑动

任何你想让交互自然的地方。

错落有致的动画编排

专业动画师不会让所有元素同时动起来,而是通过有节奏地编排各个元素,营造视觉流动感与层次感。

css 复制代码
/* ❌ 所有元素同时动起来 ------ 混乱不堪。 */
.grid-item {
  transition: all 0.3s ease;
}
​
/* ✅ 错落的时序营造出优雅的流动感。 */
.grid {
  --stagger-delay: 0;
}
​
.grid-item {
  opacity: 0;
  transform: translateY(20px);
  transition: 
    opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--stagger-delay) * 0.1s);
}
​
.grid-item.animate {
  opacity: 1;
  transform: translateY(0);
}
​
/* 通过 JavaScript 设置阶梯式延迟动画 */
/* 
grid.querySelectorAll('.grid-item').forEach((item, index) => {
  item.style.setProperty('--stagger-delay', index);
}); 
*/
​
/* 基于方向的错落时序控制 */
.navigation {
  display: flex;
}
​
.nav-item {
  opacity: 0;
  transform: translateY(-10px);
  transition: 
    opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1),
    transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
​
.nav-item:nth-child(1) { transition-delay: 0.1s; }
.nav-item:nth-child(2) { transition-delay: 0.15s; }
.nav-item:nth-child(3) { transition-delay: 0.2s; }
.nav-item:nth-child(4) { transition-delay: 0.25s; }
​
.navigation.loaded .nav-item {
  opacity: 1;
  transform: translateY(0);
}

妙在哪里: 错落动画能营造视觉节奏,引导用户按照逻辑顺序浏览界面内容。它让动画看起来像是精心编排的,而非杂乱无章。

使用场景: 页面加载动效、列表逐项显现、导航栏出现等场合中,通过错落的动画打造清晰的视觉层级,引导用户注意力。

"预期与跟随" 动画原则

专业级动画中通常包含预备动作(anticipation)和跟随动作(follow-through)

css 复制代码
/* ❌ 直接生硬的运动*/
.basic-button:hover {
  transform: scale(1.1);
}
​
/* ✅ 预期+行动+善后 */
.pro-button {
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
​
.pro-button:hover {
  animation: button-hover 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
​
@keyframes button-hover {
  0% {
    transform: scale(1);
  }
  15% {
    /* 预期: 略微收缩 */
    transform: scale(0.98);
  }
  50% {
    /* 过程中: 略微大于最终状态 */
    transform: scale(1.08);
  }
  100% {
    /* 善后: 最终状态 */
    transform: scale(1.05);
  }
}
​
/* 高级技巧:带预备动作的加载旋转器 */
.spinner {
  width: 40px;
  height: 40px;
  border: 3px solid #f3f3f3;
  border-top: 3px solid #3498db;
  border-radius: 50%;
  animation: spin-with-anticipation 1.2s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
}
​
@keyframes spin-with-anticipation {
  0% { transform: rotate(0deg) scale(1); }
  25% { transform: rotate(90deg) scale(0.9); }
  50% { transform: rotate(180deg) scale(1.1); }
  75% { transform: rotate(270deg) scale(0.95); }
  100% { transform: rotate(360deg) scale(1); }
}
​
/* 带有预备动作的卡片翻转动画*/
.card {
  transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  transform-style: preserve-3d;
}
​
.card:hover {
  animation: card-flip 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
​
@keyframes card-flip {
  0% { transform: rotateY(0deg) scale(1); }
  20% { transform: rotateY(-10deg) scale(0.98); }
  50% { transform: rotateY(90deg) scale(1.02); }
  100% { transform: rotateY(180deg) scale(1); }
}

妙在哪里: 这是因为它模拟了现实世界中物体的运动方式 ------在真实世界里,没有任何东西是瞬间改变方向的。

"预备动作"让动画看起来更有目的性,更"灵性",给用户带来更真实自然的体验。

使用场景

  • 按钮交互(Button interactions)
  • 卡片翻转(Card flips)
  • Loading(Loading states)

几乎任何你想让交互变得更有个性、更吸引人的地方,都可以使用预备与跟随动效。

图层分离策略

专业人士会将动画分离到不同的图层,以避免冲突,并实现复杂且协调的运动。

css 复制代码
/* ❌ 所有动画都集中在同一个元素上------导致 transform 属性相互冲突 */
.messy-card {
  transition: all 0.3s ease;
}
​
.messy-card:hover {
  transform: scale(1.05) rotate(2deg) translateY(-10px);
  box-shadow: 0 20px 40px rgba(0,0,0,0.1);
  border-color: blue;
}
​
/* ✅ 分层 ------ 每个元素承担特定的职责*/
.card-container {
  /* 容器层负责元素的位置控制和缩放变换*/
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
​
.card-content {
  /* 内容层负责旋转和细微的动作变化 */
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  transition-delay: 0.1s;
}
​
.card-shadow {
  /* 专用阴影元素 */
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  border-radius: inherit;
  z-index: -1;
  transition: 
    transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
    opacity 0.3s ease;
}
​
.card-container:hover {
  transform: translateY(-8px) scale(1.02);
}
​
.card-container:hover .card-content {
  transform: rotate(1deg);
}
​
.card-container:hover .card-shadow {
  transform: translateY(4px) scale(1.1);
  opacity: 0.3;
}
​
/* 高级技巧:多层加载动画 */
.loader {
  position: relative;
}
​
.loader-bg {
  /* 背景脉冲动画*/
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
​
.loader-bar {
  /* 进度条 */
  animation: progress 3s cubic-bezier(0.16, 1, 0.3, 1) infinite;
}
​
.loader-shimmer {
  /* 闪烁效果 */
  animation: shimmer 1.5s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
​
@keyframes pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}
​
@keyframes progress {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
​
@keyframes shimmer {
  0% { transform: translateX(-100%) skewX(-15deg); }
  100% { transform: translateX(200%) skewX(-15deg); }
}
​

妙在哪里:职责分离让每个元素可以拥有独立的时序和行为,使复杂动画更易维护和调试。

使用场景

  • 复杂卡片交互
  • 多阶段加载状态
  • 视差滚动效果

任何需要多个元素协调动画的场景。

性能优先的动画架构

专业人士从一开始就设计动画以保证高性能,而不是事后才进行优化。

css 复制代码
/* ❌ 性能噩梦 */
.slow-animation {
  transition: all 0.3s ease;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
​
.slow-animation:hover {
  width: 200px;
  height: 100px;
  margin: 20px;
  padding: 20px;
  box-shadow: 0 20px 40px rgba(0,0,0,0.2);
  background: linear-gradient(45deg, red, blue);
}
​
/* ✅ 性能优化的架构 */
.fast-animation {
  /* 预优化动画 */
  will-change: transform, opacity;
  transform: translateZ(0); /* 强制使用 gpu 图层 */
  backface-visibility: hidden; /* 防止动画闪烁 */
​
  /* 仅对合成器属性进行动画*/
  transition: 
    transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
​
.fast-animation::before {
  /* 预先创建开销大的动画效果 */
  content: '';
  position: absolute;
  top: -50%;
  left: -50%;
  right: -50%;
  bottom: -50%;
  background: linear-gradient(45deg, red, blue);
  opacity: 0;
  z-index: -1;
  transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
​
.fast-animation:hover {
  transform: scale(1.05) translateY(-2px);
}
​
.fast-animation:hover::before {
  opacity: 1;
}
​
/* 使用容器查询实现响应式动画 */
.container {
  container-type: size;
}
​
@container (width < 600px) {
  .fast-animation {
    /* 在小屏设备上减少动画效果 */
    transition-duration: 0.2s;
  }
​
  .fast-animation:hover {
    transform: scale(1.02) translateY(-1px);
  }
}
​
/* 尊重用户偏好设置 */
@media (prefers-reduced-motion: reduce) {
  .fast-animation {
    transition: none;
  }
​
  .fast-animation:hover {
    /* 静态替代方案 */
    opacity: 0.8;
  }
}
​
/* 关键性能设置 */
.animation-container {
  /* 限制布局偏移 */
  contain: layout style paint;
​
  /* 为动画效果进行优化 */
  will-change: transform;
  transform: translateZ(0);
​
  /* 防止子像素渲染问题 */
  backface-visibility: hidden;
  perspective: 1000px;
}

合成器(Compositor)属性 指那些只会触发"合成"阶段、不会引发重新布局或重绘的属性,浏览器能利用 GPU 加速这些动画,从而获得更流畅的性能表现。
"子像素渲染"是浏览器在进行字体或图形边缘渲染时的技术细节。常见的问题包括:

  • 动画或缩放过程中元素出现模糊、锯齿、抖动;
  • 元素在不同设备分辨率下位置或边界出现 0.5px 的偏差;
  • 滑动或过渡中边框不清晰、字体发虚;

妙在哪里:打好动画的性能基础,意味着无论动画多复杂,都能保持流畅。配合浏览器的优化机制,而不是与之对抗

使用场景:写动画就要考虑!

要点

六个变成动画高手的秘诀:

  • 尽量使用transform 写动效 --- 坚持使用 GPU 优化属性,确保流畅
  • 真实的物理引擎🐶--- 使用模拟真实运动的曲线,营造自然感
  • 错落有致的动画编排 --- 通过时序创造视觉流动和层次感
  • "预期与跟随" 动画原则--- 通过真实运动原则赋予动画个性
  • 图层分离策略 --- 将复杂动画拆解为可管理、协调的部分
  • 性能优先的动画架构 --- 从零开始构建高性能动画设计

下一步

开始在当前项目中实践这些秘诀:

  • 审查现有动画,找出性能瓶颈
  • 用基于物理的缓动曲线替换通用缓动
  • 为最重要的交互添加预备动作
  • 在构建复杂动画前搭建性能基础

掌握这些技巧,让你的动画拥有用户能感知和记住的精致专业品质。良好代码与卓越用户体验的差别,往往就在这些细节里。

相关推荐
崔庆才丨静觅12 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了13 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅13 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅13 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅14 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊14 小时前
jwt介绍
前端
爱敲代码的小鱼14 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax