在我的职业生涯投入开发之前,我在 After Effects 中做了很多动态图形工作。 但即使有这样的背景,我仍然发现网络上的动画非常令人困惑。
视频图形按特定比例设计,然后导出。 完毕! 但是网络上没有任何“导出设置”。 我们只是将代码推向世界,我们的动画必须适应它们登陆的任何设备。
那么让我们来谈谈响应式动画吧! 我们如何最好地在狂野的网络上制作动画? 我们将介绍一些通用方法、一些特定于 GSAP 的技巧和一些运动原理。 让我们从一些框架开始……
这个动画将如何使用?
Zach Saucier 关于响应式动画的文章 建议在开始编写代码之前退后一步考虑最终结果。
动画会是一个在应用程序的多个部分中重复出现的模块吗? 它是否需要扩展? 牢记这一点有助于确定动画的缩放方法,避免浪费精力。
这是一个很好的建议。 一个 巨大 设计响应式动画的一部分是了解该动画是否需要以及如何缩放,然后从一开始就选择正确的方法。
大多数动画分为以下几类:
- 固定: 图标或加载器等在所有设备上保持相同大小和纵横比的动画。 这里没有什么可担心的! 在那里硬编码一些像素值,然后继续你的一天。
- 流体: 需要在不同设备间流畅调整的动画。 大多数布局动画都属于这一类。
- 有针对性: 特定于特定设备或屏幕尺寸的动画,或在特定断点处发生重大变化的动画,例如仅桌面动画或依赖于特定设备交互的交互,如触摸或悬停。
流畅且有针对性的动画需要不同的思维方式和解决方案。 让我们来看看…
流体动画
As 安迪·贝尔 说: 成为浏览器的导师,而不是它的微观管理者——给浏览器一些可靠的规则和提示,然后让它为访问它的人做出正确的决定。
(这里有 幻灯片 从那个演示文稿中。)
流畅的动画就是让浏览器完成艰苦的工作。 只需从一开始就使用正确的单位,许多动画就可以轻松地适应不同的上下文。 如果你调整这支笔的大小,你可以看到动画使用 视口单位 随着浏览器的调整流畅地缩放:
紫色框甚至会在不同的断点处改变宽度,但是当我们使用百分比来移动它时,动画也会随之缩放。
动画布局属性,如 left
和 top
可能会导致布局重排和抖动的“janky”动画,因此尽可能坚持变换和不透明度。
不过,我们不仅限于这些单位——让我们来看看其他一些可能性。
SVG 单位
我喜欢使用 SVG 的一件事是我们可以使用 SVG 用户单元来制作开箱即用的响应式动画。 线索就在名字里—— 可扩展 矢量图形。 在 SVG-land 中,所有元素都绘制在特定坐标处。 SVG 空间就像一张无限大的方格纸,我们可以在其中排列元素。 这 viewBox
定义了我们可以看到的方格纸的尺寸。
viewBox="0 0 100 50”
在下一个演示中,我们的 SVG viewBox
is 100
单位宽和 50
单位高。 这意味着如果我们通过 100
沿 x 轴单位,它将始终移动其父 SVG 的整个宽度,无论 SVG 有多大或多小! 给演示调整大小以查看。
在 HTML 领域中,根据父容器的宽度为子元素设置动画是一个小技巧。 到目前为止,我们必须使用 JavaScript 来获取父级的宽度,这在制作动画时很容易 from
一个变换的位置,但在制作动画时有点复杂 to
正如您在以下演示中看到的那样。 如果您的终点是一个转换后的位置并且您调整了屏幕大小,则您必须手动调整该位置。 凌乱……🤔
如果您确实在调整大小时调整了值,请记住 去抖动,甚至在浏览器完成调整大小后触发该功能。 调整大小侦听器每秒触发大量事件,因此更新每个事件的属性对于浏览器来说是很多工作。
但是,这个动画减速带很快就会成为过去! 请打鼓……🥁
集装箱单位! 可爱的东西。 在我写这篇文章的时候,它们只在 Chrome 和 Safari 中工作——但也许当你读到这篇文章时,我们也会有 Firefox。 在下一个演示中查看它们的实际效果。 看那些小伙子们走! 与父元素相关的动画是不是很令人兴奋!
此浏览器支持数据来自 我可以用吗,其中有更多细节。 数字表示浏览器支持该版本及更高版本的功能。
桌面版
铬 | 火狐 | IE | 边缘 | Safari |
---|---|---|---|---|
105 | 没有 | 没有 | 105 | 16.0 |
手机/平板电脑
Android Chrome浏览器 | 安卓Firefox | Android | iOS的Safari浏览器 |
---|---|---|---|
106 | 没有 | 106 | 16.0 |
使用 FLIP 实现流畅的布局过渡
正如我们之前提到的,在 SVG-land 中,每个元素都整齐地放置在一个网格上,并且非常容易响应式地四处移动。 在 HTML 领域,它要复杂得多。 为了构建响应式布局,我们使用了一系列不同的定位方法和布局系统。 在网络上制作动画的主要困难之一是 很多 对布局的更改是不可能动画的。 也许一个元素需要从位置移动 relative
至 fixed
,或者 flex 容器的一些子容器需要在视口周围平滑移动。 也许一个元素甚至需要重新设置父级并移动到 DOM 中的一个全新位置。
棘手,是吗?
出色地。 FLIP 技术可以挽救这一天。 它使我们能够轻松地为这些不可能的事情制作动画。 基本前提是:
- 姓氏::抓取过渡中涉及的元素的初始位置。
- 名::移动元素并抓取最终位置。
- 反转:计算出第一个和最后一个状态之间的变化,并应用变换将元素反转回其原始位置。 这使它看起来元素仍在 第一 位置,但实际上不是。
- 播放:删除反转变换并为其设置动画 伪造 第一 国家对 最后 州。
这是一个使用 GSAP 的 FLIP 插件的演示,它为您完成了所有繁重的工作!
如果您想了解更多有关香草实现的信息,请访问 Paul Lewis 的 博客文章 — 他是 FLIP 技术背后的大脑。
流畅地缩放 SVG
你找到我了……这不是 真 动画提示。 但是正确设置舞台对于好的动画来说是必不可少的! 默认情况下 SVG 可以很好地缩放,但是我们可以控制它如何进一步缩放 preserveAspectRatio
,当 SVG 元素的纵横比和 viewBox
纵横比不同。 它的工作方式与 background-position
和 background-size
CSS 中的属性。 声明由对齐值(background-position
)和一个 满足 or 切片 参考 (background-size
).
至于那些 Meet and Slice 参考资料—— slice
就像 background size: cover
及 meet
就像 background-size: contain
.
preserveAspectRatio="MidYMax slice"
— 对齐到 x 轴的中间,y 轴的底部,并按比例放大以覆盖整个视口。preserveAspectRatio="MinYMin meet"
— 对齐 x 轴左侧,y 轴顶部,并在保持整体的同时按比例放大viewBox
可见。
汤姆米勒 通过使用更进一步 overflow: visible
在 CSS 和包含元素中显示“stage left”和“stage right”,同时保持高度受限:
对于响应式 SVG 动画,可以很方便地使用 SVG 视图框来创建一个在特定浏览器宽度下裁剪和缩放的视图,同时当浏览器宽度大于该宽度时,还可以在左右显示更多的 SVG 动画临界点。 我们可以通过在 SVG 上添加可见的溢出并将其与
max-height
包装器以防止 SVG 垂直缩放太多。
流畅地缩放画布
Canvas 对于复杂动画的性能要好得多 很多 移动部件比动画 SVG 或 HTML DOM,但它本质上也更复杂。 你必须为那些性能提升而努力! 与 SVG 具有可爱的响应单元和开箱即用的缩放功能不同, 必须受到领导和微观管理。
我喜欢设置我的 因此它的工作方式与 SVG(我可能有偏见)非常相似,具有可在其中工作的可爱的单位系统和固定的纵横比。
每次发生变化时也需要重新绘制,所以请记住延迟重新绘制,直到浏览器完成调整大小或去抖动!
乔治·弗朗西斯 也把这个放在一起 可爱的小图书馆 它允许您定义一个 Canvas viewBox
属性和 preserveAspectRatio
— 与 SVG 完全一样!
有针对性的动画
您有时可能需要对动画采取不那么流畅和更有针对性的方法。 与台式机相比,移动设备的空间要少得多,动画汁的性能也要少得多。 因此,向移动用户提供精简动画是有意义的,甚至可能没有动画:
有时,最好的移动响应动画根本就不是动画! 对于移动 UX,优先考虑让用户快速消费内容而不是等待动画完成。 移动动画应该增强内容、导航和交互,而不是延迟它。 埃里克·范霍尔茨
为了做到这一点,我们可以使用媒体查询来定位特定的视口大小,就像我们在使用 CSS 样式时所做的那样! 这是一个简单的演示,展示了使用媒体查询处理的 CSS 动画和处理的 GSAP 动画 gsap.matchMedia()
:
这个演示的简单性隐藏了一堆魔法! JavaScript 动画需要更多的设置和清理才能仅在一种特定的屏幕尺寸下正常工作。 我过去曾见过人们刚刚在 CSS 中隐藏动画的恐怖事件 opacity: 0
,但动画仍然在后台运行,消耗资源。 😱
如果屏幕尺寸不再匹配,则需要将动画杀死并释放以进行垃圾回收,并且需要将受动画影响的元素清除任何引入运动的内联样式,以防止与其他样式发生冲突。 直到......为止 gsap.matchMedia()
,这是一个繁琐的过程。 我们必须跟踪每个动画并手动管理所有这些。
gsap.matchMedia()
取而代之的是,您可以轻松地将动画代码放入一个函数中,该函数仅在特定 媒体查询 火柴。 然后,当它不再匹配时,所有 GSAP 动画和 滚动触发器 在该函数中自动恢复。 弹出动画的媒体查询为您完成了所有艰苦的工作。 它在 GSAP 3.11.0 中,它改变了游戏规则!
我们也不仅仅局限于屏幕尺寸。 有一个 大量的媒体功能 钩入!
(prefers-reduced-motion) /* find out if the user would prefer less animation */
(orientation: portrait) /* check the user's device orientation */
(max-resolution: 300dpi) /* check the pixel density of the device */
在下面的演示中,我们添加了一个检查 prefers-reduced-motion
这样任何发现动画迷失方向的用户都不会被周围的事物所困扰。
并查看 Tom Miller 的另一个有趣的演示,他使用设备的纵横比来调整动画:
跳出框框思考,超越屏幕尺寸
考虑响应式动画不仅仅是屏幕尺寸。 不同的设备允许不同的交互,如果你不考虑这一点,很容易陷入困境。 如果你在 CSS 中创建悬停状态,你可以使用 hover
媒体功能测试用户是否 小学 输入机制可以悬停在元素上。
@media (hover: hover) {
/* CSS hover state here */
}
来自的一些建议 杰克怀特利:
很多时候,我们的动画基于浏览器宽度,天真地假设桌面用户想要悬停状态。 过去我个人遇到过很多问题,我会切换到桌面布局 > 1024px,但可能会在 JS 中进行触摸检测——导致布局不匹配,其中布局用于桌面,但 JS 用于移动设备。 这些天我依靠悬停和指针来确保奇偶性并处理 ipad Pros 或 windows 表面(可以根据封面是否向下改变指针类型)
/* any touch device: */
(hover: none) and (pointer: coarse)
/* iPad Pro */
(hover: none) and (pointer: coarse) and (min-width: 1024px)
然后,我将结合我的 CSS 布局查询和我的 JavaScript 查询,因此我将输入设备视为主要因素 支持的 按宽度,而不是相反。
ScrollTrigger 提示
如果您使用的是 GSAP 滚动触发器插件,您可以使用一个方便的小实用程序来轻松识别设备的触摸功能: ScrollTrigger.isTouch
.
0
– 不要触碰 (仅限指针/鼠标)1
– 仅触摸 设备(如电话)2
– 设备可以接受 触摸 输入和 鼠标/指针 (如 Windows 平板电脑)
if (ScrollTrigger.isTouch) {
// any touch-capable device...
}
// or get more specific:
if (ScrollTrigger.isTouch === 1) {
// touch-only device
}
响应式滚动触发动画的另一个技巧……
下面的演示是水平移动图像库,但宽度会根据屏幕大小而变化。 如果您在擦洗动画进行到一半时调整屏幕大小,最终可能会出现损坏的动画和陈旧的值。 这是一个常见的减速带,但很容易解决! 将取决于屏幕大小的计算弹出到函数值中并设置 invalidateOnRefresh:true
. 这样,当浏览器调整大小时,ScrollTrigger 将为您重新计算该值。
奖金 GSAP 书呆子提示!
在移动设备上,浏览器地址栏通常会在您滚动时显示和隐藏。 这算作一个调整大小事件,并将触发一个 ScrollTrigger.refresh()
. 这可能并不理想,因为它可能会导致动画跳跃。 添加了 GSAP 3.10 ignoreMobileResize
. 它不会影响浏览器栏的行为,但会阻止 ScrollTrigger.refresh()
从射击 仅触摸设备上的小垂直调整大小。
ScrollTrigger.config({
ignoreMobileResize: true
});
运动原理
我想我会给你留下一些在网络上使用动画时要考虑的最佳实践。
距离和缓和
响应式动画很容易忘记的一个小而重要的事情是速度、动量和距离之间的关系! 好动画 应该模仿现实世界 感觉可信,并且在现实世界中需要更长的时间才能覆盖更远的距离。 注意你的动画行进的距离,并确保使用的持续时间和缓动在与其他动画的上下文中有意义。
您还可以经常对具有更远距离的元素应用更显着的缓动以显示增加的动量:
对于某些用例,根据屏幕宽度更动态地调整持续时间可能会有所帮助。 在下一个演示中,我们将使用 gsap.utils
钳制我们从当前得到的值 window.innerWidth
到一个合理的范围内,然后我们将该数字映射到一个持续时间。
间距和数量
要记住的另一件事是不同屏幕尺寸下元素的间距和数量。 报价 史蒂芬肖:
如果您在窗口周围放置了某种环境动画(视差、云、树木、五彩纸屑、装饰品等),请确保它们根据屏幕尺寸缩放和/或调整数量。 大屏幕可能需要更多的元素散布在各处,而小屏幕只需要几个即可达到相同的效果。
我喜欢 奥弗维希尼亚 将动画视为一个舞台。 添加和删除元素不仅是一种形式,它可以是整体编排的一部分。
在设计响应式动画时,挑战不是如何将相同的内容塞入视口以使其“适合”,而是如何管理现有内容集以传达相同的意图。 这意味着有意识地选择要添加哪些内容,以及删除哪些内容。 通常在动画世界中,事物不只是弹出或弹出框架。 将元素视为进入或退出“舞台”是有道理的,以一种具有视觉和主题意义的方式动画化过渡。
这就是很多。 如果您有更多响应式动画提示,请在评论部分弹出。 如果有什么超级有用的,我会把它们添加到这个信息概要中!
附录
来自的另一条注释 汤姆米勒 当我准备这篇文章时:
对于您的响应式动画文章,我可能为时已晚,但我强烈建议“在构建之前完成所有动画”。 我目前正在用“移动版本”改造一些网站动画。 谢天谢地
gsap.matchMedia
…但我当然希望我们从一开始就知道会有单独的移动布局/动画。
我想我们都很感激这个“提前计划”的提示是在最后一刻才出现的。 谢谢,汤姆,祝你改装好运。