DEV Community

Cover image for Future of CSS: Scroll Animations
Andrew Bone
Andrew Bone

Posted on

Future of CSS: Scroll Animations

Today we're going to be looking at scroll based animations as a part of animation-timeline, at the moment if you want to link and animation to scroll you have to listen for the scroll event in JS and update, either, the styles directly or some CSS variables that trickle down. But coming soon we have the ability to define a timeline other than elapsed seconds/milliseconds, as usual with these posts support for this feature isn't really there yet but it's slowly being rolled out (chrome canary has it at time of writing).

demo of pages tumbling away on the z axis

What is an Animation Timeline?

Historically an animation's timeline is the amount of time from when an animation starts to when it finishes, you may be used to seeing something like this.

.fade-element {
  animation: fade-animation-name 300ms linear;
}

@keyframes fade-animation-name {
  0% {
    opacity: 0;
  }

  100% {
    opacity: 1;
  }
}
Enter fullscreen mode Exit fullscreen mode

With this animation as soon as the animations start it takes 300ms for .fade-element to go from 0 opacity to 1 opacity. Because the animation function is linear, we know that if we look at this animation at 210ms opacity will be 0.7. Looking into different animation functions is beyond the scope of this blog, but let me know if you'd like me to cover it.

Imagine, then, if we could stop using time as our only timeline and instead could use percentage of an element that is on screen or how far we are between scroll position 400px and 600px.

This is exactly what an animation timeline is. We use two new CSS properties called animation-timeline and animation-range.

.fade-element {
  animation: fade-animation-name linear;
  animation-timeline: scroll();
  animation-range: 0 100vh;
}
Enter fullscreen mode Exit fullscreen mode

What are Scroll Animation Timelines?

As we sort of touched on in the previous section there are two types of scroll timeline they are Scroll Progress Timeline and View Progress Timeline.

Scroll Progress Timeline

This timeline is connected to the scroll position of a container, you can choose which container and also which axis.

To use the scroll timeline, you must set your animation-timeline to scroll(). As you can see, this is a CSS function and it takes two parameters.

First parameter:
This is the element whose bar should be used.

  • nearest (default) - first ancestor with a scroll in either plane.
  • root - root element (body).

Second parameter:
The axis to be used.

  • block (default) - The block axis this changes based on writing mode but in English this is vertical (up and down).
  • inline - The inline axis again this changes based on writing mode but in English is horizontal (left and right).
  • vertical - Always vertical (up and down).
  • horizontal - Always horizontal (left and right).
.fade-element {
  animation: fade-animation-name linear;
  animation-timeline: scroll(block root);
}
Enter fullscreen mode Exit fullscreen mode

By default, a scroll timeline will use the entire page from 0% scrolled to 100% scrolled but that might not always be what you want. You might want to only run the animation for the first 50% of your site or the first 100vh. With the animation-range property it's easy to set this up.

.fade-element {
  animation: fade-animation-name linear;
  animation-timeline: scroll(block root);
  animation-range: 20vh 80vh;
}
Enter fullscreen mode Exit fullscreen mode

The animation-range property does change a little depending on which timeline type you use but with scroll it simple is start scroll position and end scroll position with a default of 0% 100%.

View Progress Timeline

A view timeline is based on a component and its relation to the view port. The timeline for this type is view() but only has one parameter which is the axis to be used.

.fade-element {
  animation: fade-animation-name linear;
  /* this could be block | inline | vertical | horizontal */
  animation-timeline: scroll(block); 
}
Enter fullscreen mode Exit fullscreen mode

As I alluded to earlier the animation-range property has changed here too as now we have 6 different ranges that can be used these are cover, entry, exit, entry-crossing, exit-crossing and contain. With these you can run different animations on an element depending on which range it is in.

cover
This range starts when the element first touches the bottom of the screen and ends when the last part of the element exits the screen.

entry
This range starts when the element first touches the bottom of the screen and ends when the last part of the element is fully on screen.

exit
This range starts when the element first starts leaving the screen and ends when the last part of the element is fully off screen.

entry-crossing
This is the same as entry.

exit-crossing
This is the same as exit.

contain
This range starts when the element is full on screen screen and ends when the element first starts leaving the screen.

@bramus has a great tool you can use to help visualise what these mean.

.fade-element {
  animation: fade-animation-name linear;
  animation-timeline: scroll(block); 
  animation-range: entry;
}
Enter fullscreen mode Exit fullscreen mode

The View() timeline introduces one last CSS property called view-timeline-inset. This property changes the location of the page's start and end points. It takes a percentage of the width or height, depending on the axis, and can be positive or negative.

.fade-element {
  animation: fade-animation-name linear;
  animation-timeline: scroll(block); 
  animation-range: entry;
  view-timeline-inset: 10%;
}
Enter fullscreen mode Exit fullscreen mode

Demos

There was a little demo right at the start of the post just to whet your appetite, if you want to look over the code for that one here's the sandbox but here are another couple of demos to show what is possible.

Scroll animation

In this demo I have a sticky header that is 100vh and I scroll down an animations plays revealing the content behind it. I also have to move the main content as we scroll in order to make sure it appears static.

Here's a gif just in case it's not made it to your browser by the time you read this.

fallback elevator animation

Exit/Entry animation

Here I am exaggerating the exit and entry of elements making them appear to bounce in (the bounce effect is achieved with new CSS linear easing function) and zoom away.

Again here's a fallback gif just in case.

fallback bounce in animation

The end

Wow, CSS really has picked up the pace! There seems to be so much to keep up with, not that I mind. What new features would you like to see in CSS?

Thanks so much for reading. If you'd like to connect with me outside of Dev here are my twitter and linkedin come say hi 😊.

Top comments (17)

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

Nice work, I feel seasick

Collapse
 
link2twenty profile image
Andrew Bone

And isn't that what life is all about?

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

Yeah, it’s not the vomit, it’s the journey

Collapse
 
abdulrahilsheikh profile image
abdulrahilsheikh

Great work man 🔥

Collapse
 
alexmgp7 profile image
Alexander

Nice

Collapse
 
link2twenty profile image
Andrew Bone

Thank you ☺️

Collapse
 
cadje profile image
Michael Gaderer

Thanks for sharing

Collapse
 
jamstra profile image
Jam Straw

Amazing information.

Collapse
 
link2twenty profile image
Andrew Bone

It's going to be so good when it's landed in stable everywhere! ☺️

Collapse
 
joeljaison394 profile image
Joel Jaison

Nice work

Collapse
 
link2twenty profile image
Andrew Bone

Thank you ☺️

Collapse
 
jeevankaree profile image
Jeevan Kumar Karre

That's a good one, thanks for sharing

Collapse
 
link2twenty profile image
Andrew Bone

It's going to allow for some really cool websites isn't it!

Collapse
 
citronbrick profile image
CitronBrick • Edited

Fantabulous

Collapse
 
link2twenty profile image
Andrew Bone

Thank you ☺️

Collapse
 
jran_benker_eb4564c7863d profile image
Jöran Benker

exit-crossing not the same as exit
entry-crossing not the same as entry

When the principal box is larger than the scrollport you can observe a difference between the entry-crossing and entry as well as between the exit-crossing and exit.

To see this in action, check out these examples:
entry-crossing vs entry
exit-crossing vs exit

Collapse
 
murhafsousli profile image
Murhaf Sousli • Edited

Unfortunately, this only works when the fixed element animation is relative to the root scroll. the animation cannot be applied via a scrollable parent, otherwise they will move up with the scroll.