这是用户在 2024-6-19 10:32 为 https://motion.dev/blog/do-you-still-need-framer-motion?ref=ibelick 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

May 29, 2024 2024 年 5 月 29 日

Do you still need Framer Motion?
您还需要 Framer Motion 吗?

Matt Perry 马特·佩里

Time flies: I released the first version of Framer Motion over five years ago. My goal was (and still is) to make an API that is simpler than animating with CSS, but with all advanced capabilities of a JS library.
时间过得真快:五年前我发布了 Framer Motion 的第一个版本。我的目标是(现在仍然是)创建一个比 CSS 动画更简单的 API,但具有 JS 库的所有高级功能。

Animation in CSS has always been limited, often in surprising ways. For example, with CSS it's always been impossible to animate elements when they enter the DOM. With Framer Motion, it's as simple as:
CSS 中的动画一直受到限制,而且常常以令人惊讶的方式受到限制。例如,使用 CSS 时,总是不可能在元素进入 DOM 时为其添加动画效果。使用 Framer Motion,一切就这么简单:

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

Likewise, it's always been impossible to animate transforms independently, use spring physics, add scroll-linked animations, or make complex layout animations.
同样,独立地为变换设置动画、使用弹簧物理、添加滚动链接动画或制作复杂的布局动画始终是不可能的。

But five years is a long time, and CSS continues to improve. Many things that used to be hard or impossible are now surprisingly easy. So for five years of Framer Motion, here are five new CSS features that mean you might not need it anymore.
但五年是一段很长的时间,而且 CSS 还在不断改进。许多过去很难或不可能的事情现在变得出奇的简单。因此,在 Framer Motion 的五年里,这里有五个新的 CSS 功能,这意味着您可能不再需要它了。

1. Enter animations 1.输入动画

We've just seen how easy it is to make an enter animation in Framer Motion. So easy, mundane even, that over the years I've forgotten that this is technically a feature.
我们刚刚看到了在 Framer Motion 中制作输入动画是多么容易。如此简单,甚至平凡,多年来我已经忘记了这在技术上是一个功能。

When Framer Motion was first created, animating elements from an initial visual state using just CSS was impossible. You needed a sprinkle of JavaScript and even a little hackery.
当 Framer Motion 首次创建时,仅使用 CSS 从初始视觉状态对元素进行动画处理是不可能的。您需要一点 JavaScript 甚至一点黑客技术。

First, the element is styled with CSS.
首先,该元素使用 CSS 设计样式。

#my-element {
opacity: 0;
transition: opacity 0.5s;
}

Then, after adding the element to the DOM, change the value we want to animate (in this case opacity) using a little JavaScript:
然后,将元素添加到 DOM 后,使用一些 JavaScript 更改我们想要设置动画的值(在本例中为 opacity ):

const element = document.getElementById("my-element")

element.style.opacity = 1

You'd think, given the transition defined in the CSS, this would be enough to trigger an animation. It doesn't.
您可能会认为,考虑到 CSS 中定义的 transition ,这足以触发动画。事实并非如此。

Because 1 is set before the element's styles are calculated, 1 is now considered the "initial" value, not 0.
由于 1 是在计算元素样式之前设置的,因此 1 现在被视为“初始”值,而不是 0

To fix this, you can first force a style recalculation.
要解决此问题,您可以首先强制重新计算样式。

element.getBoundingClientRect()
element.style.opacity = 1

This kind of read/write distributed across an app, if not tightly managed, can lead to style and layout thrashing, which is very bad for performance.
这种分布在应用程序中的读/写如果没有严格管理,可能会导致样式和布局抖动,这对性能非常不利。

Alternatively, you can wait a couple animation frames to ensure the element has painted.
或者,您可以等待几个动画帧以确保元素已绘制。

requestAnimationFrame(() => {
requestAnimationFrame(() => {
element.style.opacity = 1
})
})

Either approach is what I'd charitably call "pretty mucky stuff". The understatement of Framer Motion's animate prop feels like a much bigger feature when looking at the alternative.
这两种方法我都亲切地称之为“相当肮脏的东西”。在考虑替代方案时,Framer Motion 的 animate 属性的轻描淡写感觉像是一个更大的功能。

However, CSS has a new trick up its sleeve, @starting-style.
然而,CSS 有一个新技巧, @starting-style

With @starting-style, we can define styles that an element will animate in from once rendered.
使用 @starting-style ,我们可以定义元素渲染后的动画样式。

#my-element {
opacity: 1;
transition: opacity 0.5s;

@starting-style {
opacity: 0;
}
}

@starting-style is available in all modern browsers. Older browsers will simply not show the animation, so it's something we can safely use today.
@starting-style 在所有现代浏览器中都可用。较旧的浏览器根本不会显示动画,因此我们今天可以安全地使用它。

Though, one interesting wrinkle with this API is that starting styles need to be defined after the normal styles, as they inexplicably share the same specificity. So although writing it like this might be your inclination:
不过,这个 API 的一个有趣的问题是,起始样式需要在正常样式之后定义,因为它们莫名其妙地共享相同的特殊性。因此,尽管您可能倾向于这样写:

#my-element {
@starting-style {
opacity: 0;
}

opacity: 1;
transition: opacity 0.5s;
}

It won't animate, as expected.
正如预期的那样,它不会动画。

2. Independent transforms
2. 独立变换

In Framer Motion (and all JS animation libraries), transforms like x, scaleX and rotate can all be animated independently of each other.
在 Framer Motion(以及所有 JS 动画库)中, xscaleXrotate 等变换都可以彼此独立地进行动画处理。

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

This used to be impossible in CSS, because transform is a single value and therefore has to be animated in its entirety. All values, together, with the same transition settings.
这在 CSS 中曾经是不可能的,因为 transform 是单个值,因此必须完整地进行动画处理。所有值都具有相同的过渡设置。

Whereas JS libraries can construct and render a new transform string every frame and thus its constituent values can start and stop animating independently, all with different transition settings.
而 JS 库可以在每帧构造和渲染一个新的 transform 字符串,因此其组成值可以独立启动和停止动画,所有这些都具有不同的过渡设置。

After many years of failed starts and dead-end proposals, CSS recently gained new shorthand properties translate, scale and rotate. Unlike transform, these can be set and animated independently of each other:
经过多年的失败启动和死胡同建议,CSS 最近获得了新的速记属性 translatescalerotate 。与 transform 不同,它们可以彼此独立地设置和动画:

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;
}

The benefit to using these values over building transform strings in JS libraries is that these animations can be hardware accelerated.
与在 JS 库中构建 transform 字符串相比,使用这些值的好处是这些动画可以进行硬件加速。

The downside is that they're still a halfway house towards true independent transforms. None of the individual axes can be controlled independently. So if we want a velocity-based x/y animation, or animate scaleX separately from scaleY, we need to rely on another new CSS feature, @property.
缺点是它们仍然是实现真正独立转换的中途。没有一个单独的轴可以被独立控制。因此,如果我们想要基于速度的 x / y 动画,或者将 scaleXscaleY 分开制作动画,我们需要依赖另一个新的 CSS 功能 @property

@property allows us to give browsers some type information on CSS variables. This unlocks the ability to animate them with CSS/WAAPI.
@property 允许我们向浏览器提供一些 CSS 变量的类型信息。这解锁了使用 CSS/WAAPI 为它们制作动画的能力。

For instance, if we want to animate rotateX and rotateY with different easing curves, we could first define variables with @property:
例如,如果我们想使用不同的缓动曲线对 rotateXrotateY 进行动画处理,我们可以首先使用 @property 定义变量:

@property --rotate-x {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}

@property --rotate-y {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}

Then use these variables in a transform/rotate string.
然后在 transform / rotate 字符串中使用这些变量。

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;
}

However, the big caveat with animating CSS variables is that they're slow, because they always trigger paint. Even though we're only using these two values in a transform, because of this paint it's still way slower to animate with CSS variables than building transform strings once a frame via a JS library.
然而,动画 CSS 变量的一个重要警告是它们很慢,因为它们总是触发绘制。尽管我们只在 transform 中使用这两个值,但由于这种绘制,使用 CSS 变量制作动画仍然比通过 JS 库在一帧中构建 transform 字符串要慢得多。

3. Springs 3. 弹簧

In all the Framer Motion examples given so far, you may have noticed a lack of transition settings. This is because Motion attempts to provide some sensible, dynamic defaults, and for transforms, these are springs.
在到目前为止给出的所有 Framer Motion 示例中,您可能已经注意到缺少 transition 设置。这是因为 Motion 试图提供一些合理的动态默认值,而对于变换来说,这些默认值就是弹簧。

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

Springs are a bedrock of the library. Velocity from a gesture or interrupted animation is fed into the next animation, so UIs feel more tactile, responsive, even playful.
泉水是图书馆的基石。手势或中断动画的速度会被输入到下一个动画中,因此 UI 感觉更有触觉、响应更快,甚至更有趣。

Springs have long been impossible with CSS, but recently it gained the linear() easing function.
Spring 长期以来在 CSS 中是不可能实现的,但最近它获得了 linear() 缓动功能。

linear() is such a slam dunk idea that it was probably the shortest period time I've seen an API proposed and then shipped in notorious laggard Safari.
linear() 是一个绝妙的想法,这可能是我见过的 API 提出并在臭名昭著的落后者 Safari 中发布的最短时间。

Not to be confused with linear (no function brackets), the linear() easing function accepts a series of points and interpolates between them linearly (hence the name). Provide enough points and they can "draw" the easing curve of a spring, or a bounce, or any other custom easing curve.
不要与 linear (无函数括号)混淆, linear() 缓动函数接受一系列点并在它们之间线性插值(因此得名)。提供足够的点,他们可以“绘制”弹簧的缓动曲线、弹跳或任何其他自定义缓动曲线。

A spring defined via linear() might look like this:
通过 linear() 定义的 spring 可能如下所示:

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
);

Obviously, it isn't intended that you write out a linear() definition yourself. I actually lifted this one straight from an online linear() generator.
显然,您并不打算自己编写 linear() 定义。实际上,我直接从在线 linear() 生成器中提取了这个。

The developer experience here is pretty poor, having to copy/paste these definitions from an outside tool rather than just passing options to a spring() function. The feeling of springs can be difficult to nail, so going back and forth between one of these tools is tedious.
这里的开发人员体验非常差,必须从外部工具复制/粘贴这些定义,而不是仅仅将选项传递给 spring() 函数。弹簧的感觉可能很难确定,因此在这些工具中来回切换是很乏味的。

The other downside is that they're predefined easing curves, not a real physics simulation running on each style's actual value and velocity. So they're not going to provide that same feeling when picking up the velocity from a user gesture or interrupted animation.
另一个缺点是它们是预定义的缓动曲线,而不是在每种样式的实际值和速度上运行的真实物理模拟。因此,当从用户手势或中断的动画中获取速度时,它们不会提供相同的感觉。

However, they can look pretty convincing for certain animations, so it can be a good-enough, lightweight option in many cases.
然而,对于某些动画来说,它们看起来非常令人信服,因此在许多情况下它可能是一个足够好的轻量级选项。

4. Scroll-linked animations
4. 滚动链接动画

There are two types of scroll animations: Scroll-triggered and scroll-linked.
滚动动画有两种类型:滚动触发式和滚动链接式。

Scroll-triggered animations are normal time-based animations that get triggered when an element appears in view. These are trivial in Framer Motion thanks to the whileInView prop.
滚动触发的动画是正常的基于时间的动画,当元素出现在视图中时就会触发。由于 whileInView 属性,这些在 Framer Motion 中都是微不足道的。

<motion.div initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} />

Although possible to hack together, there's still not a good solution for scroll-triggered animations in CSS today.
虽然可以一起破解,但目前 CSS 中的滚动触发动画仍然没有一个好的解决方案。

Conversely, rather than being driven by time, scroll-linked animations link values directly to scroll progress. In Framer Motion these are created by composing MotionValues:
相反,滚动链接动画不是由时间驱动,而是将值直接链接到滚动进度。在 Framer Motion 中,这些是通过组合 MotionValue 来创建的:

const { scrollYProgress } = useScroll()

// Map scroll progress to x
const x = useTransform(scrollYProgress, [0, 1], [0, 500])

return <motion.div style={{ x }} />

CSS does have a new feature for scroll-linked animations. Two, actually: The new scroll() and view() animation timelines.
CSS 确实有一个用于滚动链接动画的新功能。实际上是两个:新的 scroll()view() 动画时间线。

Either can be assigned to the animation-timeline style to drive animations via scroll progress instead of time:
两者都可以分配给 animation-timeline 样式,通过滚动进度而不是时间来驱动动画:

div {
animation-name: fadeAnimation;
animation-timeline: scroll();
}

@keyframes fadeAnimation {
from {
transform: translateX(0px);
}
to {
transform: translateX(500px);
}
}

The difference between the two is that scroll() is used to track the scroll progress of the viewport or scrollable element, while view() is used to detect the progress of an element as it moves through a viewport/element.
两者之间的区别在于, scroll() 用于跟踪视口或可滚动元素的滚动进度,而 view() 用于检测元素在视口/元素中移动时的进度。

The great thing about these new timelines is when a style animation can be hardware accelerated, like transform or opacity, these scroll animations will also run completely off the main thread, ensuring scroll animations stay smooth even as your site is performing heavy lifting.
这些新时间线的伟大之处在于,当样式动画可以进行硬件加速时,例如 transformopacity ,这些滚动动画也将完全脱离主线程运行,确保即使您的网站执行繁重,滚动动画也能保持流畅提升。

Framer Motion does have some preliminary support for accelerated scroll animations via the new ScrollTimeline JS API, while maintaining compatibility with older browsers. But more work needs to be done to support ViewTimeline.
Framer Motion 确实通过新的 ScrollTimeline JS API 对加速滚动动画提供了一些初步支持,同时保持了与旧版浏览器的兼容性。但需要做更多的工作来支持 ViewTimeline

One downside to the CSS timeline is that when we want to do anything fancier, like base an animation on scroll velocity, or dampen motion, we have to resort to CSS variable trickery.
CSS 时间轴的一个缺点是,当我们想要做任何更奇特的事情时,例如基于滚动速度的动画或阻尼运动,我们必须诉诸 CSS 变量技巧。

Not only are these effects arguably more straightforward to compose using Framer Motion's useVelocity and useSpring, because they rely on CSS variables they run on the main thread and trigger paint, so they're actually less performant than using JavaScript.
使用 Framer Motion 的 useVelocityuseSpring 可以说这些效果不仅可以更直接地组合,而且因为它们依赖于在主线程上运行并触发绘制的 CSS 变量,因此它们实际上比使用 JavaScript 的性能要差。

5. Layout animations 5.布局动画

Framer Motion has a powerful layout animation API that can take any two layouts and animate between them using transform.
Framer Motion 具有强大的布局动画 API,可以采用任意两个布局并使用 transform 在它们之间制作动画。

It's great for animating values that are usually unanimatable, like justify-content:
它非常适合为通常不可设置动画的值设置动画,例如 justify-content

It seems overkill for this simple example, but the nice thing to notice is it illustrates that you get to create your layouts using your preferred CSS, like grid, flexbox etc, across different breakpoints, and Motion will figure out the required transform animations in real time.
对于这个简单的示例来说,这似乎有些过头了,但值得注意的是,它说明了您可以使用您喜欢的 CSS(如网格、Flexbox 等)跨不同的断点创建布局,并且 Motion 将计算出所需的 transform 动画实时。

The API is super simple too. Just tag animating elements with the layout prop.
API 也非常简单。只需使用 layout 属性标记动画元素即可。

<motion.div layout />

Framer Motion's layout animations go way beyond the classic FLIP technique, as they perform scale correction on infinitely deep trees, including distortion on border-radius and box-shadow, ensuring any layout can animate rather than just the top-level element.
Framer Motion 的布局动画远远超出了经典的 FLIP 技术,因为它们对无限深的树执行比例校正,包括 border-radiusbox-shadow 上的失真,确保任何布局都可以进行动画处理,而不仅仅是顶级元素。

It can also perform shared layout animations across completely different trees by providing two elements the same layoutId prop.
它还可以通过为两个元素提供相同的 layoutId 属性来在完全不同的树上执行共享布局动画。

<motion.div layoutId="modal" />

Without Framer Motion, an animation like this one would have been prohibitively complex to write and maintain.
如果没有 Framer Motion,像这样的动画的编写和维护将会极其复杂。

But now, there's the View Transition API, a browser-native API that can animate between two different views and has been positioned by some as a replacement for Motion's layout animations.
但现在,有了 View Transition API,这是一种浏览器原生 API,可以在两个不同视图之间进行动画处理,并被一些人定位为 Motion 布局动画的替代品。

The differences are extensive and could be a post of their own, so I'll attempt to be brief.
差异很大,可能会单独写一篇文章,所以我会尽量简短。

It works by wrapping DOM updates with document.startViewTransition():
它的工作原理是用 document.startViewTransition() 包装 DOM 更新:

document.startViewTransition(updateDOM)

By default this will crossfade the whole viewport to its new visual state.
默认情况下,这会将整个视口交叉淡入淡出到新的视觉状态。

Note: The following demos will only animate in browsers supporting the View Transitions API.
注意:以下演示仅在支持 View Transitions API 的浏览器中显示动画。

The way this practically works is a new pseudo DOM is created on top of the page. This is made up of a screenshot of the previous view, and a live screenshot of the new view. These are then crossfaded.
它的实际工作方式是在页面顶部创建一个新的伪 DOM。它由前一个视图的屏幕截图和新视图的实时屏幕截图组成。然后将它们交叉淡入淡出。

For this switch example, this default effect is pretty poor, but for full page transitions it's quite good. This very site uses a similar effect when navigating between pages.
对于这个切换示例,这个默认效果相当差,但对于整页转换来说它相当不错。这个网站在页面之间导航时使用了类似的效果。

For this switch, we can improve it by adding a unique view-transition-name style to the toggle element.
对于这个开关,我们可以通过向切换元素添加独特的 view-transition-name 样式来改进它。

<div style={{ viewTransitionName: "toggle" }} />

Now, the page will still crossfade, but the toggle element will be screenshotted and crossfaded in its own layer in the pseudo DOM. It's size and position will also be animated.
现在,页面仍然会交叉淡入淡出,但 toggle 元素将被截图并在伪 DOM 中其自己的层中交叉淡入淡出。它的大小和位置也将被动画化。

For this simple example the code looks slightly more complex than Framer Motion's API, and IMO it is a pain to have to provide each element a unique ID. It's needless complexity, and becomes a pain to manage across a tree of components. view-transition: persist or similar would be better for these same-element animations.
对于这个简单的示例,代码看起来比 Framer Motion 的 API 稍微复杂一些,而且在我看来,必须为每个元素提供唯一的 ID 是一件很痛苦的事情。这是不必要的复杂性,并且跨组件树管理变得很痛苦。对于这些相同元素的动画, view-transition: persist 或类似的效果会更好。

On the other hand it doesn't get any more complex to create shared element transitions. The element with the view-transition-name can be different before and after the transition.
另一方面,创建共享元素转换并不会变得更加复杂。带有 view-transition-name 的元素在转换之前和之后可以不同。

In terms of the API, it's not great that we have to remove the view-transition-name style on the list items when a modal is opened.
就 API 而言,打开模态框时我们必须删除列表项上的 view-transition-name 样式,这不太好。

viewTransitionName: isOpen ? undefined : "container"

Framer Motion maintains layoutId stacks so you can add multiple elements with the same ID and it'll know which elements to animate to and back from.
Framer Motion 维护 layoutId 堆栈,因此您可以添加具有相同 ID 的多个元素,并且它会知道要向哪些元素设置动画和从哪些元素返回。

You can also see the images don't animate between their positions as well as in the Framer Motion example. This is because that effect was made of two layers, the outer container clipping the inner image-container. Because each named element gets screenshotted and animated in a new pseudo element, that sits in parallel to other layers (rather than maintaining their DOM hierarchy) you can encounter visual artefacts where elements were previously clipped:
您还可以看到图像在其位置之间不会像在 Framer Motion 示例中一样进行动画处理。这是因为该效果由两层组成,外部的 container 裁剪内部的 image-container 。因为每个命名元素都会在新的伪元素中进行屏幕截图和动画处理,该伪元素与其他层并行(而不是维护其 DOM 层次结构),因此您可能会遇到元素先前被剪切的视觉效果:

In Framer Motion the elements themselves are animated so you don't run into these kinds of situations.
在 Framer Motion 中,元素本身是动画的,因此您不会遇到此类情况。

That said, the pseudo DOM is a completely unique and new setup, one that opens possibilities that don't exist with the way layout animations work on the DOM itself.
也就是说,伪 DOM 是一种完全独特的新设置,它开启了布局动画在 DOM 本身上工作的方式所不存在的可能性。

For instance, we can lift a layer off the page while we crosswipe beneath it with an animated gradient mask:
例如,我们可以在使用动画渐变蒙版在其下方横向擦拭时,将图层从页面上提起:

Other fundamental differences exist with drawbacks and opportunities.
其他根本性的差异存在着缺点和机遇。

Scroll delta 滚动三角洲

View transitions are literally that: Transitions between two views. This means that if the scroll position changes during the DOM update, then every element with a view-transition-name is going to animate across the viewport by that scroll distance.
视图转换实际上就是:两个视图之间的转换。这意味着,如果滚动位置在 DOM 更新期间发生变化,则每个带有 view-transition-name 的元素都将按照该滚动距离在视口上进行动画处理。

Whereas layout animations are, unsurprisingly, literally that: Transitions between two layouts. Scroll is accounted for, so elements that have only changed position in the viewport because they scrolled aren't going to animate. Or, if they do animate because they've also changed layout, they will animate out of their new scroll position, not where they used to be drawn on screen.
毫不奇怪,布局动画的字面意思是:两个布局之间的转换。考虑了滚动,因此仅因滚动而在视口中改变位置的元素不会产生动画。或者,如果它们因为也更改了布局而进行动画处理,则它们将从新的滚动位置(而不是以前在屏幕上绘制的位置)进行动画处理。

Transform animations 变换动画

Transforms aren't layout, so in Framer Motion they can animate separately. Notice when toggling the layout here the rotation animation continues uninterrupted:
变换不是布局,因此在 Framer Motion 中它们可以单独制作动画。请注意,在此处切换布局时,旋转动画会不间断地继续:

Mixed transitions 混合过渡

When animating multiple layers with different transition settings, there's no concept in view transitions of relative layout. A parent layer could animate away from a child with a delay or slower transition (and vice versa):
当使用不同的过渡设置对多个图层进行动画处理时,相对布局的视图过渡没有概念。父层可以通过延迟或较慢的过渡以动画方式远离子层(反之亦然):

Whereas Framer Motion is aware of the relationship between these two elements and will ensure parents and children can't animate away from each other:
而 Framer Motion 知道这两个元素之间的关系,并将确保父母和孩子的动画不会彼此分开:

Interruptible animations 可中断的动画

Try clicking rapidly on the Framer Motion switch example, and then the view transitions switch example. Motion's layout animations are interruptible, whereas view transitions aren't. By default the pseudo DOM blocks pointer events, but if you do interrupt a view transition manually, the next animation will start from where the real DOM element actually is in the viewport, not where it looks like it is in the view transition.
尝试快速单击 Framer Motion 开关示例,然后单击视图转换开关示例。 Motion 的布局动画是可中断的,而视图转换则不然。默认情况下,伪 DOM 会阻止指针事件,但如果您手动中断视图转换,下一个动画将从真实 DOM 元素在视口中实际所在的位置开始,而不是从视图转换中看起来的位置开始。

Interruptibility is a table stakes animation feature, so more than anything else, this makes them completely unsuitable for these kinds of micro-interactions.
可中断性是一个赌注动画功能,因此最重要的是,这使得它们完全不适合此类微交互。

All said 都说了

Some of these differences are being addressed and while some are inherent to the concept of view transitions.
其中一些差异正在得到解决,而另一些则是视图转换概念所固有的。

All said, a choice between view transitions and layout animations is a false dichotomy. In Framer we use them both, each for their respective strengths.
总而言之,在视图转换和布局动画之间进行选择是错误的二分法。在 Framer 中,我们同时使用它们,各自发挥各自的优势。

View transitions are great at animating the entire view from one state to the other, so we use those for animations between different pages. You can create unique effects that simply aren't possible with layout animations.
视图转换非常适合将整个视图从一种状态动画到另一种状态,因此我们将它们用于不同页面之间的动画。您可以创建布局动画根本无法实现的独特效果。

Whereas layout animations are interruptible, aren't affected by scroll, can mix transition settings, and work much better with isolated parts of the page. So we use these for animating component variants.
而布局动画是可中断的,不受滚动影响,可以混合过渡设置,并且可以更好地处理页面的孤立部分。因此我们使用它们来制作组件变体的动画。

So depending on what you want to animate, view transitions may or may not be a valid alternative.
因此,根据您想要设置动画的内容,视图过渡可能是也可能不是有效的替代方案。

Bonus: Auto-height 奖励:自动高度

Okay so I promised five reasons, but this one is really exciting. I'll keep it short.
好吧,我答应了五个理由,但这一个真的很令人兴奋。我会长话短说。

Framer Motion has long been able to animate between fixed heights and auto.
Framer Motion 长期以来一直能够在固定高度和 auto 之间制作动画。

<motion.div animate={{ height: isOpen ? "auto" : 0 }} />

CSS doesn't support animating to/from auto, but with CSS5's brand new calc-size proposal, the same effect will finally be doable.
CSS 不支持 auto 之间的动画,但通过 CSS5 全新的 calc-size 提案,同样的效果终于可以实现。

li {
height: 0px;
transition: height 0.3s ease-out;
.open {
height: calc-size(auto);
}
}

No catch, just a great new feature.
没有什么问题,只是一个很棒的新功能。

So, do you still need Framer Motion?
那么,您还需要 Framer Motion 吗?

This is an amazing set of new features that have landed, or will soon land, in CSS. If you're only using Framer Motion for very specific reasons, like enter animations or height: auto, then there's a compelling argument for starting with CSS and bringing in Framer Motion only when you hit its limitations.
这是 CSS 中已经实现或即将实现的一组令人惊叹的新功能。如果您仅出于非常特定的原因使用 Framer Motion,例如输入动画或 height: auto ,那么有一个令人信服的论点是从 CSS 开始,仅在遇到其限制时才引入 Framer Motion。

For me, bias acknowledged, I simply prefer the Framer Motion API. With the peculiarities of CSS APIs, like @starting-style specificity, or the Assembly-level aesthetics of linear(), most of these new features are still simpler to achieve in Motion. Simplicity is fun to write, and more maintainable.
对我来说,承认偏见,我只是更喜欢 Framer Motion API。由于 CSS API 的特殊性,例如 @starting-style 特异性或 linear() 的汇编级美学,这些新功能中的大多数在 Motion 中仍然更容易实现。简单性写起来很有趣,而且更易于维护。

Further, there's a fidelity with Framer Motion (and JS animation libraries in general) that I don't feel CSS achieves yet. Be it true velocity-based springs, or interruptible layout animations, or even humble hover gestures that aren't weirdly polyfilled to touch devices because of the state of the web back in 2007, animations and gestures built in Framer Motion should feel better.
此外,我认为 CSS 尚未实现 Framer Motion(以及一般的 JS 动画库)的保真度。无论是真正基于速度的弹簧,还是可中断的布局动画,甚至是由于 2007 年网络状况而没有奇怪地填充到触摸设备上的简单悬停手势,Framer Motion 中内置的动画和手势应该感觉更好。

There's also an ocean of features that CSS still doesn't have, like complex timeline sequencing, exit animations, stagger, scroll-triggered animations, velocity-based springs, and many more besides.
还有大量 CSS 尚不具备的功能,例如复杂的时间轴排序、退出动画、交错、滚动触发的动画、基于速度的弹簧等等。

So, do you still need Framer Motion? Thanks to these five new CSS features, the calculus has changed, but my answer is the same as it was five years ago: Go hang out with your loved ones or something.
那么,您还需要 Framer Motion 吗?感谢这五个新的 CSS 功能,微积分发生了变化,但我的答案与五年前相同:去和你所爱的人出去玩什么的。

CONSUME 消耗

Drag to outliner or Upload
Close