Let’s Make Certainly one of These Fancy Scrolling Animations Used on Apple Product Pages

Apple is well-known for the glossy animations on their product pages. For instance, as you scroll down the web page merchandise could slide into view, MacBooks fold open and iPhones spin, all whereas displaying off the {hardware}, demonstrating the software program and telling interactive tales of how the merchandise are used.

Simply take a look at this video of the cell internet expertise for the iPad Professional:

A variety of the results that you just see there aren’t created in simply HTML and CSS. What then, you ask? Properly, it may be slightly laborious to determine. Even utilizing the browser’s DevTools gained’t at all times reveal the reply, because it typically can’t see previous a <canvas> factor.

Let’s take an in-depth take a look at certainly one of these results to see the way it’s made so you’ll be able to recreate a few of these magical results in our personal tasks. Particularly, let’s replicate the AirPods Pro product page and the shifting mild impact within the hero picture.

The fundamental idea

The thought is to create an animation identical to a sequence of pictures in fast succession. You recognize, like a flip ebook! No complicated WebGL scenes or superior JavaScript libraries are wanted.

By synchronizing every body to the consumer’s scroll place, we will play the animation because the consumer scrolls down (or again up) the web page.

Begin with the markup and kinds

The HTML and CSS for this impact may be very straightforward because the magic occurs contained in the <canvas> factor which we management with JavaScript by giving it an ID.

In CSS, we’ll give our doc a top of 100vh and make our <physique> 5⨉ taller than that to offer ourselves the mandatory scroll size to make this work. We’ll additionally match the background coloration of the doc with the background coloration of our pictures.

The very last thing we’ll do is place the <canvas>, heart it, and restrict the max-width and top so it doesn’t exceed the size of the viewport.

html {
  top: 100vh;

physique {
  background: #000;
  top: 500vh;

canvas {
  place: mounted;
  left: 50%;
  prime: 50%;
  max-height: 100vh;
  max-width: 100vw;
  remodel: translate(-50%, -50%);

Proper now, we’re in a position to scroll down the web page (although the content material doesn’t exceed the viewport top) and our <canvas> stays on the prime of the viewport. That’s all of the HTML and CSS we’d like.

Let’s transfer on to loading the pictures.

Fetching the proper pictures

Since we’ll be working with a picture sequence (once more, like a flip ebook), we’ll assume the file names are numbered sequentially in ascending order (i.e. 0001.jpg, 0002.jpg, 0003.jpg, and so forth.) in the identical listing.

We’ll write a perform that returns the file path with the variety of the picture file we would like, based mostly off of the consumer’s scroll place.

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

For the reason that picture quantity is an integer, we’ll want to show it in to a string and use padStart(4, '0') to prepend zeros in entrance of our index till we attain 4 digits to match our file names. So, for instance, passing 1 into this perform will return 0001.

That provides us a option to deal with picture paths. Right here’s the primary picture within the sequence drawn on the <canvas> factor:

As you’ll be able to see, the primary picture is on the web page. At this level, it’s only a static file. What we would like is to replace it based mostly on the consumer’s scroll place. And we don’t merely wish to load one picture file after which swap it out by loading one other picture file. We wish to draw the pictures on the <canvas> and replace the drawing with the subsequent picture within the sequence (however we’ll get to that in only a bit).

We already made the perform to generate the picture filepath based mostly on the quantity we cross into it so what we have to do now’s observe the consumer’s scroll place and decide the corresponding picture body for that scroll place.

Connecting pictures to the consumer’s scroll progress

To know which quantity we have to cross (and thus which picture to load) within the sequence, we have to calculate the consumer’s scroll progress. We’ll make an occasion listener to trace that and deal with some math to calculate which picture to load.

We have to know:

  • The place scrolling begins and ends
  • The consumer’s scroll progress (i.e. a proportion of how far the consumer is down the web page)
  • The picture that corresponds to the consumer’s scroll progress

We’ll use scrollTop to get the vertical scroll place of the factor, which in our case occurs to be the highest of the doc. That may function the start line worth. We’ll get the tip (or most) worth by subtracting the window top from the doc scroll top. From there, we’ll divide the scrollTop worth by the utmost worth the consumer can scroll down, which supplies us the consumer’s scroll progress.

Then we have to flip that scroll progress into an index quantity that corresponds with the picture numbering sequence for us to return the proper picture for that place. We will do that by multiplying the progress quantity by the variety of frames (pictures) now we have. We’ll use Math.flooring() to spherical that quantity down and wrap it in Math.min() with our most body depend so it by no means exceeds the overall variety of frames.

window.addEventListener('scroll', () => {  
  const scrollTop = html.scrollTop;
  const maxScrollTop = html.scrollHeight - window.innerHeight;
  const scrollFraction = scrollTop / maxScrollTop;
  const frameIndex = Math.min(
    frameCount - 1,
    Math.flooring(scrollFraction * frameCount)

Updating <canvas> with the proper picture

We now know which picture we have to draw because the consumer’s scroll progress adjustments. That is the place the magic of  <canvas> comes into play. <canvas> has many cool options for constructing all the pieces from games and animations to design mockup generators and all the pieces in between!

A kind of options is a technique known as requestAnimationFrame that works with the browser to replace <canvas> in a approach we couldn’t do if we have been working with straight picture information as an alternative. For this reason I went with a <canvas> method as an alternative of, say, an <img> factor or a <div> with a background picture.

requestAnimationFrame will match the browser refresh charge and allow {hardware} acceleration by utilizing WebGL to render it utilizing the system’s video card or built-in graphics. In different phrases, we’ll get tremendous clean transitions between frames — no picture flashes!

Let’s name this perform in our scroll occasion listener to swap pictures because the consumer scrolls up or down the web page. requestAnimationFrame takes a callback argument, so we’ll cross a perform that may replace the picture supply and draw the brand new picture on the <canvas>:

requestAnimationFrame(() => updateImage(frameIndex + 1))

We’re bumping up the frameIndex by 1 as a result of, whereas the picture sequence begins at 0001.jpg, our scroll progress calculation begins really begins at 0. This ensures that the 2 values are at all times aligned.

The callback perform we cross to replace the picture appears like this:

const updateImage = index => {
  img.src = currentFrame(index);
  context.drawImage(img, 0, 0);

We cross the frameIndex into the perform. That units the picture supply with the subsequent picture within the sequence, which is drawn on our <canvas> factor.

Even higher with picture preloading

We’re technically achieved at this level. However, come on, we will do higher! For instance, scrolling rapidly leads to slightly lag between picture frames. That’s as a result of each new picture sends off a brand new community request, requiring a brand new obtain.

We must always strive preloading the pictures new community requests. That approach, every body is already downloaded, making the transitions that a lot sooner, and the animation that a lot smoother!

All we’ve gotta do is loop by means of the whole sequence of pictures and cargo ‘em up:

const frameCount = 148;

const preloadImages = () => {
  for (let i = 1; i < frameCount; i++) {
    const img = new Picture();
    img.src = currentFrame(i);



A fast observe on efficiency

Whereas this impact is fairly slick, it’s additionally a variety of pictures. 148 to be actual.

Irrespective of a lot we optimize the pictures, or how speedy the CDN is that serves them, loading lots of of pictures will at all times end in a bloated web page. Let’s say now we have a number of cases of this on the identical web page. We’d get efficiency stats like this:

That is perhaps positive for a high-speed web connection with out tight information caps, however we will’t say the identical for customers with out such luxuries. It’s a tough steadiness to strike, however now we have to be conscious of everybody’s expertise — and the way our selections have an effect on them.

A couple of issues we will do to assist strike that steadiness embody:

  • Loading a single fallback picture as an alternative of the whole picture sequence
  • Creating sequences that use smaller picture information for sure gadgets
  • Permitting the consumer to allow the sequence, maybe with a button that begins and stops the sequence

Apple employs the primary possibility. In case you load the AirPods Pro page on a cell system linked to a sluggish 3G connection and, hey, the efficiency stats begin to look an entire lot higher:

8 out of 111 requests, 347 kilobytes of 2.6 megabytes transferred, 1.4 megabytes of 4.5 megabytes resources, load time of one minute and one second.

Yeah, it’s nonetheless a heavy web page. Nevertheless it’s loads lighter than what we’d get with none efficiency issues in any respect. That’s how Apple is ready to get get so many complicated sequences onto a single web page.

Additional studying

If you’re inquisitive about how these picture sequences are generated, place to begin is the Lottie library by AirBnB. The docs take you thru the fundamentals of producing animations with After Results whereas offering a simple option to embody them in tasks.

Source link

Leave a Reply

Your email address will not be published. Required fields are marked *