Modern Scroll Shadows Using Scroll-Driven Animations

Home » Modern Scroll Shadows Using Scroll-Driven Animations

Using scroll shadows, especially for mobile devices, is a subtle bit of UX that Chris has covered before (indeed, it’s one of his all-time favorite CSS tricks), by layering background gradients with different attachments, we can get shadows that are covered up when you’ve scrolled to the limits of the element.

Geoff covered a newer approach that uses the animation-timeline property. Using animation-timeline, we can tie CSS animation to the scroll position. His example uses pseudo-elements to render the scroll shadows, and animation-range to animate the opacity of the pseudo-elements based on scroll.

Here’s yet another way. Instead of using shadows, let’s use a CSS mask to fade out the edges of the scrollable element. This is a slightly different visual metaphor that works great for horizontally scrollable elements — places where your scrollable element doesn’t have a distinct border of its own. This approach still uses animation-timeline, but we’ll use custom properties instead of pseudo-elements. Since we’re fading, the effect also works regardless of whether we’re on a dark or light background.

Getting started with a scrollable element

First, we’ll define our scrollable element with a mask that fades out the start and end of the container. For this example, let’s consider the infamous table that can’t be responsive and has to be horizontally scrollable on mobile.

Let’s add the mask. We can use the shorthand and find the mask as a linear gradient that fades out on either end. A mask lets the table fade into the background instead of overlaying a shadow, but you could use the same technique for shadows.

CodePen Embed Fallback
.scrollable {
  mask: linear-gradient(to right, #0000, #ffff 3rem calc(100% - 3rem), #0000);
}

Defining the custom properties and animation

Next, we need to define our custom properties and the animation. We’ll define two separate properties, --left-fade and --right-fade, using @property. Using @property is necessary here to specify the syntax of the properties so that browsers can animate the property’s values.

@property --left-fade {
  syntax: "<length>";
  inherits: false;
  initial-value: 0;
}

@property --right-fade {
  syntax: "<length>";
  inherits: false;
  initial-value: 0;
}

@keyframes scrollfade {
  0% {
    --left-fade: 0;
  }
  10%, 100% {
    --left-fade: 3rem;
  }
  0%, 90% {
    --right-fade: 3rem;
  }
  100% {
    --right-fade: 0;
  }
}

Instead of using multiple animations or animation-range, we can define a single animation where --left-fade animates from 0 to 3rem between 0-10%, and --right-fade animates from 3rem to 0 between 90-100%. Now we update our mask to use our custom properties and tie the scroll-timeline of our element to its own animation-timeline.

Putting it all together

Putting it all together, we have the effect we’re after:

CodePen Embed Fallback

We’re still waiting for some browsers (Safari) to support animation-timeline, but this gracefully degrades to simply not fading the element at all.

Wrapping up

I like this implementation because it combines two newer bits of CSS — animating custom properties and animation-timeline — to achieve a practical effect that’s more than just decoration. The technique can even be used with scroll-snap-based carousels or cards:

CodePen Embed Fallback

It works regardless of content or background and doesn’t require JavaScript. It exemplifies just how far CSS has come lately.


Modern Scroll Shadows Using Scroll-Driven Animations originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

​ 

Leave a Comment

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