Bringing Back Parallax with Scroll-Driven Css Animations | CSS-Tricks

For a period in the 2010s, parallax was a guaranteed way to make your website “Cool”. Indeed, Chris Coyer was written about it as far back as 2008.

For there unfamiliar with the concept, parallax is a pattern in which different elements of a webpage move at varying speeds as the user scrolls, creating a three-directional, layered appractional. A True parallax effect was on only achievable using javascript. However, scroll-Dr. Driven Animations have now given us a css-only solution, which is free from the main-thread blocking that can flag javascript animations.

Parallax may have become a little click, but I think it’s Worth revisiting with this new csses feature.

Note: Scroll-Dr. Driven Animations are available on Chrome, Edge, Opera, and Firefox (Behind a Feature Flag) at the time of written. Use a supported browser when following this tutorial.

Starting code

In this example, we will apply parallax animations to the background and iCons with the three “hero” sections of a universe-themed webpage. We’ll start with some lightly styled markup featuring alternating hero and text sections while if if you include space-rested nonsense as placehlets content.

Adding Initial Animations

Let’s add an animation to the background pattern with Hero Section to modify the background position.

@keyframes parallax {
  from {
    background-position: bottom 0px center;
  }
  to {
    background-position: bottom -400px center;
  }
}

section.hero {
  /* previous code */
+ animation: parallax 3s linear;
}

Here we use the keyframes Css rule to create a start and end position for the background. Then we attach this animation to each of our hero sections using the animation Property.

By default, css animations are duration-based and run the specified selector is loaded in the dom. If you refresh your browser, you will see the animation running for three seconds as soon as the page loads.

https://www.youtube.com/watch?v=26dv5mgw10k

We do not want our animation to be triggered immediatily. INTEAD, we intend to use the page’s scroll position as a reference to calculate the animation’s program.

Scroll-Driven Animations Provide two new animation timeline CSS Functions. These additions, view() and scroll()Tell the browser what to reference when calculating the program of a css animation. We will use the view() Function Later, but for now, Let’s focus on scroll()The scroll progress timeline Couples the program of an animation to the user’s scroll position within a scroll container. Parameters can be included to change the scroll axis and controler element, but these are not health for our implementation.

Let’s use a scroll progress timeline for our animation:

section.hero {
  /* previous code */
- animation: parallax 3s linear;
+ animation: parallax linear;
+ animation-timeline: scroll(); 
}

If you refresh the page, you will notice that as you scroll down, the position of the background of Each Hero Section also changes. If you scroll back up, the animation reverses. As a bonus, this css animation is handled off the main thread and thus is not subject to blocking by any javaascript that may be running.

https://www.youtube.com/watch?v=lhjgxmvi96i

Using the View Progress Timeline

Now let’s add a new parallax layer by animating the header text and icons with Hero Section. This way, the background patterns, headers, and main page content will all appear to scroll at different speeds. We will initially use the scroll() Css Function for the Animation Timeline Here as Well.

@keyframes float {
  from {
    top: 25%;
  }
  to {
    top: 50%;
  }
}

.hero-content {
  /* previous code */
+ position: absolute;
+ top: 25%;
+ animation: float linear;
+ animation-timeline: scroll(); 
}

https://www.youtube.com/watch?v=hb0ytmmj5m

That’s not quite right. The animation for the sections further down the page is nearly don by the time they come into view. Luckily, The View Animation Timeline Solves This Problem. By setting the animation-timeline Property to view()Our animation programs based on the position of the subject within the scrollport, which is the part of the contrain that is visible when scrolling. Like the Scroll Animation Timeline, Scrolling in Reverse will also also show the animation.

Let’s Try Changing Our Animation Timeline Property for the Hero Text:

.hero-content {
  /* previous code */
- animation-timeline: scroll(); 
+ animation-timeline: view(); 
}

That looks pretty good, but there is a problem with the header content flashing into the view when scrolling back up the document. This is government the View Timeline is Calculated Based on the Original, Pre-Anaimation Positioning of the Subject Element.

https://www.youtube.com/watch?v=LCLRA2EY0_A

We can solve this by adding an inset Parameter to the view() Function. This adjusts the size of the container in which the animation will take place. According to mdn’s documentation, the “inset is used to determine was the element is in view which determines the length of the animation of the animation time. Inset-Djusted View. “

So, by using a negative value, we make the contrainer larger than the window and trigger the animation to start a little before and end a little after the subject is visible. This accounts for the fact that the subject movies during the animation.

- animation-timeline: view();
+ animation-timeline: view(-100px);

Now both the text and background animate smoothly at different speeds.

Adjusting animations using animation ranges

So far, we have employed bot scrololl and View Progress Timelines. Let’s look at another way to adjust the start and end timing of the animations using the animation-range Property. It can be used to modify where the timeline the animation will start and end.

We’ll start by adding a view() Timeline animation to the #spaceship emoji:

@keyframes launch {
  from {
    transform: translate(-100px, 200px);
  }
  to {
    transform: translate(100px, -100px);
  }
}

#spaceship {
  animation: launch;
  animation-timeline: view();
}

Again, we see the emoji returning to its 0% Position once its original unanimated position is outside of the scrollport.

https://www.youtube.com/watch?v=w1ybhvwxfx0

As discussed before, animations are based on the original Pre-Election of the Subject. Previous, we solved this by adding an inset parameter to the view() Function. We can also adjust the animation Range and Tell our animation to continue beyond 100% of the animation timeline without having to manipulate the Inset of the View Timeline Itslf.

#spaceship {
  animation: launch;
  animation-timeline: view();
+ animation-range: 0% 120%;
}

Now the animation continues until we have scrolled an extra 20% beyond the calculated scroll timeline’s normal endpoint.

https://www.youtube.com/watch?v=zzpy8xhafay

Let’s say that we want to add an animation to the #comet Emoji, but we don’t want it to start animating until it has passed 4rem from the bottom of the scrollport:

@keyframes rotate {
  from {
    transform: rotate(0deg) translateX(100px);
  }
  to {
    transform: rotate(-70deg) translateX(0px);
  }
}

#comet {
  animation: rotate linear;
  transform-origin: center 125px;
  animation-timeline: view();
  animation-range: 4rem 120%;
}

Here we see the “delayed” animation in action:

https://www.youtube.com/watch?v=wzncii4xepu

We can also Combine Animation Ranges to Run Completely Different Animations at different points with the same timeline! Let’s illustrate this by combining animation ranges for the #satellite icon at the top of the page, The result is that the first animation runs until the icon passes 80% of the scrollport, then the second animation takes over for the final 20%.

@keyframes orbit-in {
  0% {
    transform: rotate(200deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

@keyframes orbit-out {
  0% {
    transform: translate(0px, 0px);
  }
  100% {
    transform: translate(-50px, -15px);
  }
}

#satellite {
  animation: orbit-in linear, orbit-out ease;
  animation-timeline: view();
  animation-range: 0% 80%, 80% 110%;
}

https://www.youtube.com/watch?v=gnyjdxnwo

Fallbacks and accessibility

Our webpage features numerous moving elements that may cause discomfort for some users. Let’s Consider Accessibility for Motion sensitivities and incorporate the prefers-reduced-motion CSS Media Feature.

There are two passible values: no-preferenceand reduceIf we want to fin-tune the webpage with animations disabled by default and then enhance each selector with animations and associates styles, then we can use no-preference to enable them.

@media (prefers-reduced-motion: no-preference) {
  .my-selector {
    position: relative;
    top: 25%;
    animation: cool-animation linear;
    animation-timeline: scroll(); 
  }
}

For us, however, the webpage content and images will all all be visible if we disable all animations simultaneously. This can be done concry using the reduce Option. It’s important to note that this Sort of Blanket Approach works for our situation, but you should always consider the impact on your special users when implementing accessibility fatures.

@media (prefers-reduced-motion: reduce) {
  .my-selector {
    animation: none !important;
  }
}

In addition to considering accessibility, we should also take into account that scroll-Dr. Animations are not supported by all browsers at the time of written. If we care a lot about users see our animations, we can add a polyfill (direct link) to extend this functionality to currently unsupported browsers. This, however, will force the animation to run on the main thread.

Alternatively, we could decide that performance is important enough to skip the animations on unsupported browsers, thereby keeping the main thread clear. In this case, we can use the @supports Selector and include the styles only on supported browsers.

Here is the final code with everything, including the polyfill and reduced motion fallback:

Conclusion

There we go, we just re-taken a Classic Web Effect with Scroll-Driven Animations Using scrololl and View Progress Timelines. We also discusing some of the parameters that can be used to adjust animation behavior. Whether or not parallax is your thing, I like the idea that we can use a modern approach that is capable of doing what we could before… only better with a dash of processive enhancement.

More information

Ramesh Ghorai is the founder of www.livenewsblogger.com, a platform dedicated to delivering exclusive live news from across the globe and the local market. With a passion for covering diverse topics, he ensures readers stay updated with the latest and most reliable information. Over the past two years, Ramesh has also specialized in writing top software reviews, partnering with various software companies to provide in-depth insights and unbiased evaluations. His mission is to combine news reporting with valuable technology reviews, helping readers stay informed and make smarter choices.

Leave a Comment

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

Scroll to Top