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

下一步

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

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

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

相关推荐
李剑一10 分钟前
面试官:你是如何理解MVVM模型的?请你结合自己做过的项目从框架层面解释一下
前端·面试
Likeyou714 分钟前
HTML无尽射击小游戏包含源码,纯HTML+CSS+JS
javascript·css·html
tiantian_cool16 分钟前
Flutter-1
前端
前端Hardy20 分钟前
这个你一定要知道,如何使用Pandoc创建HTML网页版文档?
前端·javascript·css
前端小嘎22 分钟前
常见前端面试题 之 AI打字机效果是如何实现的?
前端·javascript
前端老鹰22 分钟前
CSS scrollbar-width:轻松定制滚动条宽度的隐藏属性
前端·css
_前端小弟23 分钟前
记录一次主题色自动适应方案
前端
Danny_FD24 分钟前
深入理解 `z-index` 与 `overflow`
前端
搞个锤子哟24 分钟前
复制文字功能写入剪切板的坑
前端