原文地址:Do you still need Framer Motion? - Motion One Blog

文章作者是 Framer Motion 和 Motion One 的作者,在这篇文章中他讨论了 CSS 动画相关的最新进展,以及这些进展是否减少了对 Framer Motion 的需求。他举例了五个新的CSS动画属性来与 Framer Motion 的实现进行对比

进入动画

CSS

CSS 新增了 @starting-style,可以定义元素渲染后的起始样式。

#my-element {
  opacity: 1;
  transition: opacity 0.5s;
 
  @starting-style {
    opacity: 0;
  }
}

Framer Motion

<motion.li
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
/>

独立的变换

CSS

CSS新增了 translatescalerotate 的简写属性,可以对这些属性进行单独的设置,而不需要通过 JS 拼接字符串的形式来实现某个属性的动画

button {
  translate: 0px 0px;
  transition:
    translate 0.2s ease-out,
    scale 0.5s ease-in-out;
}
 
@starting-style {
  button {
    translate: 0px 10px;
  }
}
 
button:hover {
  scale: 1.2;
}

另外可以通过 @property 在变量上提供一些类型信息给浏览器

@property --rotate-x {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
 
@property --rotate-y {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
 
button {
  transform: rotateX(var(--rotate-x)) rotateY(var(--rotate-y));
  // rotate: var(--rotate-x) var(--rotate-y);
  transition:
    --rotate-x 0.2s ease-out,
    --rotate-y 0.3s linear;
}
 
button:hover {
  --rotate-x: 10deg;
  --rotate-y: 20deg;
}

Framer Motion

<motion.div
  initial={{ y: 10 }}
  whileInView={{ y: 0 }}
  whileHover={{ scale: 1.2 }}
  whileTap={{ scale: 0.9, rotateX: 5 }}
/>

弹簧动画

CSS

新增了 linear() 函数,可以模拟弹簧效果。它与 linear(无括号)属性不同,linear() 函数接受一系列点,并在他们之间线性插值,提供足够的点,他们可以绘制弹簧的缓动曲线,或者弹跳和其他任何自定义的曲线。

transition: transform 2s linear(
  0, 0.009, 0.035 2.1%, 0.141, 0.281 6.7%, 0.723 12.9%, 0.938 16.7%, 1.017,
  1.077, 1.121, 1.149 24.3%, 1.159, 1.163, 1.161, 1.154 29.9%, 1.129 32.8%,
  1.051 39.6%, 1.017 43.1%, 0.991, 0.977 51%, 0.974 53.8%, 0.975 57.1%,
  0.997 69.8%, 1.003 76.9%, 1.004 83.8%, 1
);

Framer Motion

<motion.div
  initial={{ x: -100 }}
  animate={{ x: 0 }}
  transition={{ type: "spring", stiffness: 300, damping: 10 }}
/>

滚动链接动画

CSS

CSS 引入了 scroll()view() 动画时间线,可以实现滚动链接动画。任何一个都可以分配给 animation-timeline 样式,以通过滚动进度驱动动画,而不是时间

div {
  animation-name: fadeAnimation;
  animation-timeline: scroll();
}
 
@keyframes fadeAnimation {
  from {
    transform: translateX(0px);
  }
  to {
    transform: translateX(500px);
  }
}

两者之间的区别在于 scroll() 用于跟踪视口可滚动元素的滚动进度,而 view() 用于检测元素在通过视口/元素时的进度。

新时间轴的好处在于,当样式动画可以进行硬件加速时,比如 transformopacity ,这些动画动画也讲完全在主线程之外运行,确保滚动动画保持流畅。

Framer Motions

// 滚动触发
<motion.div initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} />
 
// 滚动链接
const { scrollYProgress } = useScroll()
 
// Map scroll progress to x
const x = useTransform(scrollYProgress, [0, 1], [0, 500])
 
return <motion.div style={{ x }} />

布局动画

CSS

CSS 的 View Transitions API 可以原生的在两个视图之间进行动画过渡

document.startViewTransition(updateDOM)

Framer Motion

<motion.div layoutId="modal" />

结论

尽管 CSS 新增了一些功能, Framer Motion 仍然在某些地方存在优势,例如 API的简介性、动画的精确控制、可中断、复杂时间序列、退出动画等。

作者认为,Framer Motion 在一些地方仍然具有相当大的优势,并且提供了许多 CSS 尚未实现的功能。因此,尽管 CSS的新特性改变了一些情况,但作者仍然推荐使用 Framer Motion,特别是那些寻求更高级动画功能和更好动画体验的开发者。