Table of Contents
Basic concepts
Start with tags and styles
Get the correct image
Connect the image to the user's scrolling progress
Preloading images are better
Demo!
Quick description of performance
Home Web Front-end CSS Tutorial Let's Make One of Those Fancy Scrolling Animations Used on Apple Product Pages

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

Apr 06, 2025 am 10:27 AM

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

Apple's product pages are known for their smooth animations. For example, when you scroll down the page, the product may slide into view, the MacBook will turn on, the iPhone will rotate, all of which showcase the hardware, demonstrate the software, and tell interactive stories about how the product is used.

Just check out this video of the iPad Pro mobile web experience:

Many of the effects you see there are not created using only HTML and CSS. So, you would ask? Well, this may be a little hard to figure out. Even using the browser's DevTools doesn't always reveal the answer, as it's usually impossible to see<canvas></canvas> Content outside the element.

Let's dig into one of the effects and see how it's made so that you can recreate some of these magical effects in our own projects. Specifically, let's copy dynamic light effects from AirPods Pro product pages and hero images.

Basic concepts

The idea is to create an animation, just like a series of fast-sequential images. You know, just like flipping a book! No complex WebGL scenarios or advanced JavaScript libraries are required.

By synchronizing each frame with the user's scrolling position, we can play the animation as the user scrolls the page down (or up).

Start with tags and styles

HTML and CSS for this effect are very simple, because magic happens in<canvas></canvas> Inside an element, we control it using JavaScript by assigning it ID.

In CSS, we set the height of the document to 100vh and our content height to 5 times higher than 100vh to give us the necessary scroll length to make it work. We also match the background color of the document with the background color of the image. The last thing we have to do is position<canvas></canvas> element, center it and limit the maximum width and height so that it does not exceed the size of the viewport.

 <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>
Copy after login

Now we can scroll down the page (even if the content does not exceed the viewport height), our<canvas></canvas> Still at the top of the viewport. That's all we need for HTML and CSS.

Let's continue loading the image.

Get the correct image

Since we will use the image sequence (again, like flipping a book), we will assume that the file names are numbered in ascending order in succession (i.e., 0001.jpg, 0002.jpg, 0003.jpg, etc.) in the same directory.

We will write a function that returns the path and number of the desired image file based on the user's scroll position.

 <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>
Copy after login

Since the image number is an integer, we need to convert it to a string and use padStart(4, '0') to precede our index until we reach the four digits to match our filename. For example, passing 1 to this function will return 0001.

This gives us a way to process image paths. This is<canvas></canvas> The first image in the sequence drawn on the element:

As you can see, the first image is on the page. At this point, it is just a static file. What we want is to update it based on the user's scrolling position. We not only want to load one image file, but then replace it by loading another image file. We hope to be<canvas></canvas> Draw the image on top and update the drawing with the next image in the sequence (but we'll discuss it later).

We have created a function that generates the path of the image file based on the numbers we pass in, so what we need to do now is track the user's scroll position and determine the image frame corresponding to that scroll position.

Connect the image to the user's scrolling progress

To understand which number we need to pass (and therefore which image we want to load) in the sequence, we need to calculate the user's scrolling progress. We will create an event listener to track the event and process some mathematical calculations to calculate the image to be loaded.

We need to know:

  • Where the scroll starts and ends
  • User scrolling progress (i.e. percentage of page scrolling down by the user)
  • Image corresponding to user scrolling progress

We will use scrollTop to get the vertical scroll position of the element, in this case the top of the document. This will be used as the starting value. We will get the end (or maximum) value by subtracting the window height from the document scroll height. From there, we divide scrollTop value by the maximum value the user can scroll down, which will give us the user's scrolling progress.

We then need to convert that scrolling progress to an index number corresponding to our sequence of image numbers in order to return the correct image for that position. We can do this by multiplying the number of progress by the number of frames (number of images) we have. We will round that number down using Math.floor() and wrap it in Math.min() and our maximum number of frames so that it never exceeds the total number of frames.

 <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>
Copy after login

Update with the correct image<canvas></canvas>

We now know which image to draw when the user's scrolling progress changes. This is<canvas></canvas> where the magic works.<canvas></canvas> With lots of cool features to build everything from games and animations to design model generators and in between!

One of these features is a method called requestAnimationFrame , which works with the browser to update<canvas></canvas> , if we are using a direct image file instead of<canvas></canvas> , we can't do this. This is my choice<canvas></canvas> Method instead of e.g. img element or background image<div> The reason. <code>requestAnimationFrame will match the browser refresh rate and enable hardware acceleration by rendering with the device's video card or integrated graphics card using WebGL. In other words, we will get a very smooth transition between frames – no image flickering!

Let's call this function in our scroll event listener to exchange images when the user scrolls up or down the page. requestAnimationFrame takes a callback parameter, so we will pass a function to update the image source and<canvas></canvas> Draw a new image on:

 <code>requestAnimationFrame(() => updateImage(frameIndex 1))</code>
Copy after login

We increment frameIndex by 1, because while the image sequence starts at 0001.jpg, our scrolling progress calculations actually start at 0. This ensures that the two values ​​are always aligned.

The callback function we pass to the update image looks like this:

 <code>const updateImage = index => { img.src = currentFrame(index); context.drawImage(img, 0, 0); }</code>
Copy after login

We pass frameIndex to the function. This sets the image source using the next image in the sequence, which is drawn in our<canvas></canvas> on the element.

Preloading images are better

Technically, we're done now. But please, we can do better! For example, fast scrolling can cause a little lag between image frames. This is because each new image sends a new network request, requiring a new download.

We should try to preload the image with new network requests. This way, each frame has been downloaded, making the transition faster and the animation smoother!

All we have to do is loop through the entire sequence of images and load them:

 <code>const frameCount = 148; const preloadImages = () => { for (let i = 1; i </code>
Copy after login

Demo!

Quick description of performance

While this effect is very cool, it is also a lot of images. To be precise, it is 148 pieces.

No matter how we optimize images, or how fast the CDNs are to provide them, loading hundreds of images will always cause the page to bloat. Suppose we use this feature multiple times on the same page. We may get the following performance statistics:

This may be fine for users with high-speed internet connections and low data caps, but we can't say that for users without this convenience. It's a difficult issue to balance, but we have to pay attention to everyone's experience – and how our decisions affect them.

There are a few things we can do to help achieve this balance, including:

 <code>- 加载单个后备图像而不是整个图像序列- 为某些设备创建使用较小图像文件的序列- 允许用户启用序列,也许可以使用启动和停止序列的按钮苹果采用第一种方法。如果您在连接到缓慢的3G 连接的移动设备上加载AirPods Pro 页面,那么,性能统计数据开始看起来好多了:是的,它仍然是一个繁重的页面。但它比我们根本没有任何性能考虑的情况下要轻得多。这就是苹果能够将如此多的复杂序列放到单个页面上的方式。 #### 进一步阅读如果您有兴趣了解这些图像序列是如何生成的,一个好的起点是AirBnB 的Lottie 库。文档将引导您完成使用After Effects 生成动画的基础知识,同时提供一种在项目中轻松包含它们的方法。</code>
Copy after login

The above is the detailed content of Let's Make One of Those Fancy Scrolling Animations Used on Apple Product Pages. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1662
14
PHP Tutorial
1262
29
C# Tutorial
1235
24
Google Fonts   Variable Fonts Google Fonts Variable Fonts Apr 09, 2025 am 10:42 AM

I see Google Fonts rolled out a new design (Tweet). Compared to the last big redesign, this feels much more iterative. I can barely tell the difference

How to Create an Animated Countdown Timer With HTML, CSS and JavaScript How to Create an Animated Countdown Timer With HTML, CSS and JavaScript Apr 11, 2025 am 11:29 AM

Have you ever needed a countdown timer on a project? For something like that, it might be natural to reach for a plugin, but it’s actually a lot more

HTML Data Attributes Guide HTML Data Attributes Guide Apr 11, 2025 am 11:50 AM

Everything you ever wanted to know about data attributes in HTML, CSS, and JavaScript.

How We Created a Static Site That Generates Tartan Patterns in SVG How We Created a Static Site That Generates Tartan Patterns in SVG Apr 09, 2025 am 11:29 AM

Tartan is a patterned cloth that’s typically associated with Scotland, particularly their fashionable kilts. On tartanify.com, we gathered over 5,000 tartan

A Proof of Concept for Making Sass Faster A Proof of Concept for Making Sass Faster Apr 16, 2025 am 10:38 AM

At the start of a new project, Sass compilation happens in the blink of an eye. This feels great, especially when it’s paired with Browsersync, which reloads

How to Build Vue Components in a WordPress Theme How to Build Vue Components in a WordPress Theme Apr 11, 2025 am 11:03 AM

The inline-template directive allows us to build rich Vue components as a progressive enhancement over existing WordPress markup.

PHP is A-OK for Templating PHP is A-OK for Templating Apr 11, 2025 am 11:04 AM

PHP templating often gets a bad rap for facilitating subpar code — but that doesn&#039;t have to be the case. Let’s look at how PHP projects can enforce a basic

Programming Sass to Create Accessible Color Combinations Programming Sass to Create Accessible Color Combinations Apr 09, 2025 am 11:30 AM

We are always looking to make the web more accessible. Color contrast is just math, so Sass can help cover edge cases that designers might have missed.

See all articles