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

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

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)

Demystifying Screen Readers: Accessible Forms & Best Practices Demystifying Screen Readers: Accessible Forms & Best Practices Mar 08, 2025 am 09:45 AM

This is the 3rd post in a small series we did on form accessibility. If you missed the second post, check out "Managing User Focus with :focus-visible". In

Adding Box Shadows to WordPress Blocks and Elements Adding Box Shadows to WordPress Blocks and Elements Mar 09, 2025 pm 12:53 PM

The CSS box-shadow and outline properties gained theme.json support in WordPress 6.1. Let&#039;s look at a few examples of how it works in real themes, and what options we have to apply these styles to WordPress blocks and elements.

Making Your First Custom Svelte Transition Making Your First Custom Svelte Transition Mar 15, 2025 am 11:08 AM

The Svelte transition API provides a way to animate components when they enter or leave the document, including custom Svelte transitions.

Working With GraphQL Caching Working With GraphQL Caching Mar 19, 2025 am 09:36 AM

If you’ve recently started working with GraphQL, or reviewed its pros and cons, you’ve no doubt heard things like “GraphQL doesn’t support caching” or

Classy and Cool Custom CSS Scrollbars: A Showcase Classy and Cool Custom CSS Scrollbars: A Showcase Mar 10, 2025 am 11:37 AM

In this article we will be diving into the world of scrollbars. I know, it doesn’t sound too glamorous, but trust me, a well-designed page goes hand-in-hand

Show, Don't Tell Show, Don't Tell Mar 16, 2025 am 11:49 AM

How much time do you spend designing the content presentation for your websites? When you write a new blog post or create a new page, are you thinking about

Building an Ethereum app using Redwood.js and Fauna Building an Ethereum app using Redwood.js and Fauna Mar 28, 2025 am 09:18 AM

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

What the Heck Are npm Commands? What the Heck Are npm Commands? Mar 15, 2025 am 11:36 AM

npm commands run various tasks for you, either as a one-off or a continuously running process for things like starting a server or compiling code.

See all articles