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.
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.
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();
}
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.
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.
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.
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:
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%;
}
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-preference
and reduce
If 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.