目录
基本概念
从标记和样式开始
获取正确的图像
将图像连接到用户的滚动进度
预加载图像更好
演示!
关于性能的快速说明
首页 web前端 css教程 让我们制作Apple产品页面上使用的那些精美的滚动动画之一

让我们制作Apple产品页面上使用的那些精美的滚动动画之一

Apr 06, 2025 am 10:27 AM

Let's Make One of Those Fancy Scrolling Animations Used on Apple Product Pages

苹果产品页面以其流畅的动画而闻名。例如,当您向下滚动页面时,产品可能会滑入视野,MacBook 会打开,iPhone 会旋转,所有这些都展示了硬件,演示了软件,并讲述了产品如何使用的互动故事。

只需查看 iPad Pro 移动网页体验的这段视频:

您在那里看到的许多效果并非仅使用 HTML 和 CSS 创建的。那么,您会问?好吧,这可能有点难以弄清楚。即使使用浏览器的 DevTools 也并非总能揭示答案,因为它通常无法看到 <canvas></canvas> 元素之外的内容。

让我们深入研究其中一种效果,看看它是如何制作的,以便您可以在我们自己的项目中重新创建一些这些神奇的效果。具体来说,让我们复制 AirPods Pro 产品页面和英雄图像中的动态光效。

基本概念

这个想法是创建一个动画,就像一系列快速连续的图像一样。您知道,就像翻书一样!不需要复杂的 WebGL 场景或高级 JavaScript 库。

通过将每一帧与用户的滚动位置同步,我们可以在用户向下(或向上)滚动页面时播放动画。

从标记和样式开始

此效果的 HTML 和 CSS 非常简单,因为魔法发生在 <canvas></canvas> 元素内部,我们通过赋予其 ID 来使用 JavaScript 控制它。

在 CSS 中,我们将文档的高度设置为 100vh,并将我们的内容高度设置为比 100vh 高 5 倍,以便为我们提供必要的滚动长度以使其工作。我们还将文档的背景颜色与图像的背景颜色相匹配。我们要做的最后一件事是定位 <canvas></canvas> 元素,将其居中,并限制最大宽度和高度,使其不超过视口的尺寸。

<code>html {
  height: 100vh;
}

body {
  background: #000;
  height: 500vh;
}

canvas {
  position: fixed;
  left: 50%;
  top: 50%;
  max-height: 100vh;
  max-width: 100vw;
  transform: translate(-50%, -50%);
}</code>
登录后复制

现在,我们可以向下滚动页面(即使内容没有超过视口高度),我们的 <canvas></canvas> 仍然位于视口顶部。这就是我们需要的全部 HTML 和 CSS。

让我们继续加载图像。

获取正确的图像

由于我们将使用图像序列(再次,就像翻书一样),我们将假设文件名按升序顺序连续编号(即 0001.jpg、0002.jpg、0003.jpg 等)在同一目录中。

我们将编写一个函数,根据用户的滚动位置返回所需图像文件的路径和编号。

<code>const currentFrame = index => (
  `https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`
)</code>
登录后复制

由于图像编号是整数,我们需要将其转换为字符串并使用 padStart(4, '0') 在我们的索引前面添加零,直到达到四位数字以匹配我们的文件名。例如,将 1 传递到此函数将返回 0001。

这给了我们一种处理图像路径的方法。这是在 <canvas></canvas> 元素上绘制的序列中的第一张图像:

如您所见,第一张图像在页面上。此时,它只是一个静态文件。我们想要的是根据用户的滚动位置更新它。我们不仅希望加载一个图像文件,然后通过加载另一个图像文件来替换它。我们希望在 <canvas></canvas> 上绘制图像,并使用序列中的下一张图像更新绘图(但我们稍后会讨论)。

我们已经创建了根据我们传入的数字生成图像文件路径的函数,因此我们现在需要做的是跟踪用户的滚动位置并确定该滚动位置对应的图像帧。

将图像连接到用户的滚动进度

要了解我们需要传递哪个数字(以及因此要加载哪个图像)在序列中,我们需要计算用户的滚动进度。我们将创建一个事件侦听器来跟踪该事件并处理一些数学计算来计算要加载的图像。

我们需要知道:

  • 滚动开始和结束的位置
  • 用户的滚动进度(即用户向下滚动页面的百分比)
  • 与用户滚动进度对应的图像

我们将使用 scrollTop 获取元素的垂直滚动位置,在本例中是文档顶部。这将作为起始值。我们将通过从文档滚动高度减去窗口高度来获取结束(或最大)值。从那里,我们将 scrollTop 值除以用户可以向下滚动的最大值,这将给我们用户的滚动进度。

然后,我们需要将该滚动进度转换为与我们的图像编号序列对应的索引号,以便为该位置返回正确的图像。我们可以通过将进度数乘以我们拥有的帧数(图像数)来做到这一点。我们将使用 Math.floor() 将该数字向下取整,并将其包装在 Math.min() 中以及我们的最大帧数中,以便它永远不会超过总帧数。

<code>window.addEventListener('scroll', () => {  
  const scrollTop = html.scrollTop;
  const maxScrollTop = html.scrollHeight - window.innerHeight;
  const scrollFraction = scrollTop / maxScrollTop;
  const frameIndex = Math.min(
    frameCount - 1,
    Math.floor(scrollFraction * frameCount)
  );
});</code>
登录后复制

使用正确的图像更新 <canvas></canvas>

我们现在知道在用户的滚动进度发生变化时需要绘制哪个图像。这就是 <canvas></canvas> 的魔力发挥作用的地方。<canvas></canvas> 具有许多很酷的功能,用于构建从游戏和动画到设计模型生成器以及介于两者之间的一切!

这些功能之一是称为 requestAnimationFrame 的方法,它与浏览器一起工作以更新 <canvas></canvas>,如果我们使用的是直接图像文件而不是 <canvas></canvas>,我们就无法做到这一点。这就是我选择 <canvas></canvas> 方法而不是例如 img 元素或具有背景图像的 <div> 的原因。<code>requestAnimationFrame 将匹配浏览器刷新率并通过使用 WebGL 使用设备的视频卡或集成显卡进行渲染来启用硬件加速。换句话说,我们将获得帧之间非常平滑的过渡——没有图像闪烁!

让我们在我们的滚动事件侦听器中调用此函数,以便在用户向上或向下滚动页面时交换图像。requestAnimationFrame 采用回调参数,因此我们将传递一个函数来更新图像源并在 <canvas></canvas> 上绘制新图像:

<code>requestAnimationFrame(() => updateImage(frameIndex   1))</code>
登录后复制

我们将 frameIndex 增加 1,因为虽然图像序列从 0001.jpg 开始,但我们的滚动进度计算实际上是从 0 开始。这确保了这两个值始终对齐。

我们传递给更新图像的回调函数如下所示:

<code>const updateImage = index => {
  img.src = currentFrame(index);
  context.drawImage(img, 0, 0);
}</code>
登录后复制

我们将 frameIndex 传递给函数。这使用序列中的下一张图像设置图像源,该图像绘制在我们的 <canvas></canvas> 元素上。

预加载图像更好

从技术上讲,我们现在已经完成了。但是,拜托,我们可以做得更好!例如,快速滚动会导致图像帧之间出现一点滞后。这是因为每个新图像都会发送一个新的网络请求,需要一个新的下载。

我们应该尝试预加载图像新的网络请求。这样,每个帧都已下载,使过渡更快,动画更流畅!

我们要做的就是循环遍历整个图像序列并加载它们:

<code>const frameCount = 148;

const preloadImages = () => {
  for (let i = 1; i </code>
登录后复制

演示!

关于性能的快速说明

虽然这种效果非常酷,但它也是很多图像。确切地说,是 148 张。

无论我们如何优化图像,或者提供它们的 CDN 多么快速,加载数百张图像总是会导致页面膨胀。假设我们在同一页面上多次使用此功能。我们可能会得到如下性能统计数据:

对于高速互联网连接且数据上限不严格的用户来说,这可能没问题,但对于没有这种便利的用户来说,我们不能这么说。这是一个难以平衡的问题,但我们必须注意每个人的体验——以及我们的决定如何影响他们。

我们可以做一些事情来帮助取得这种平衡,包括:

<code>
- 加载单个后备图像而不是整个图像序列
- 为某些设备创建使用较小图像文件的序列
- 允许用户启用序列,也许可以使用启动和停止序列的按钮

苹果采用第一种方法。如果您在连接到缓慢的 3G 连接的移动设备上加载 AirPods Pro 页面,那么,性能统计数据开始看起来好多了:

是的,它仍然是一个繁重的页面。但它比我们根本没有任何性能考虑的情况下要轻得多。这就是苹果能够将如此多的复杂序列放到单个页面上的方式。

#### 进一步阅读

如果您有兴趣了解这些图像序列是如何生成的,一个好的起点是 AirBnB 的 Lottie 库。文档将引导您完成使用 After Effects 生成动画的基础知识,同时提供一种在项目中轻松包含它们的方法。

</code>
登录后复制

以上是让我们制作Apple产品页面上使用的那些精美的滚动动画之一的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1662
14
CakePHP 教程
1419
52
Laravel 教程
1313
25
PHP教程
1262
29
C# 教程
1235
24
Google字体可变字体 Google字体可变字体 Apr 09, 2025 am 10:42 AM

我看到Google字体推出了新设计(Tweet)。与上一次大型重新设计相比,这感觉更加迭代。我几乎无法分辨出区别

如何使用HTML,CSS和JavaScript创建动画倒计时计时器 如何使用HTML,CSS和JavaScript创建动画倒计时计时器 Apr 11, 2025 am 11:29 AM

您是否曾经在项目上需要一个倒计时计时器?对于这样的东西,可以自然访问插件,但实际上更多

HTML数据属性指南 HTML数据属性指南 Apr 11, 2025 am 11:50 AM

您想了解的有关HTML,CSS和JavaScript中数据属性的所有信息。

我们如何创建一个在SVG中生成格子呢模式的静态站点 我们如何创建一个在SVG中生成格子呢模式的静态站点 Apr 09, 2025 am 11:29 AM

格子呢是一块图案布,通常与苏格兰有关,尤其是他们时尚的苏格兰语。在Tar​​tanify.com上,我们收集了5,000多个格子呢

使Sass更快的概念证明 使Sass更快的概念证明 Apr 16, 2025 am 10:38 AM

在一个新项目开始时,Sass汇编发生在眼睛的眨眼中。感觉很棒,尤其是当它与browsersync配对时,它重新加载

如何在WordPress主题中构建VUE组件 如何在WordPress主题中构建VUE组件 Apr 11, 2025 am 11:03 AM

内联式模板指令使我们能够将丰富的VUE组件构建为对现有WordPress标记的逐步增强。

php是A-OK用于模板 php是A-OK用于模板 Apr 11, 2025 am 11:04 AM

PHP模板通常会因促进Subpar代码而变得不良说唱,但这并不是这样的情况。让我们看一下PHP项目如何执行基本的

编程SASS创建可访问的颜色组合 编程SASS创建可访问的颜色组合 Apr 09, 2025 am 11:30 AM

我们一直在寻求使网络更容易访问。颜色对比只是数学,因此Sass可以帮助涵盖设计师可能错过的边缘案例。

See all articles