Scroll Based Animations with ZERO Javascript 🔥🔥
Published: 2021-03-10 10:12:14

At some point of time, most of us have used GSAP, Javascript `IntersectionObserver` or jQuery(c'mon guys, its 2021... using jQuery instead of javascript is like using IE for web development), in the foreseeable future, this can be done using CSS!

No, it's not a typo and I'm not insane. It's possible using the (drumroll please...) `@scroll-timeline`. However, everything is not fine and dandy, this is still in draft and is supported only by Chrome 89(after turning on an experimental flag).

>The [Scroll-linked Animations]  (https://drafts.csswg.org/scroll-animations-1/) is a new addition to CSS that defines a way for creating animations that are linked to a scroll offset of a scroll container. The specification is still in draft, and in no way finalised nor official, it already has experimental support in Chromium.

In sometime, maybe in a year or so, all major browsers will support it(who cares about Internet Explorer anyway? Even Microsoft ditched it).

###Setup
I'll be using codepen to demonstrate the animations. Let's start by enabling the expiremental feature. Go to chrome://flags and enable "Experimental Web Platform features".

Add some basic HTML -


```html
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=">
	<title></title>
</head>

<body>
	<p>scroll down</p>

<div class="container">
	<div class="inner">
		<h1>Scroll based animations in CSS is so coooool</h1>
		<img src="https://images.unsplash.com/photo-1542831371-29b0f74f9713?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80" alt="placeholder image" class="image" id="image">
	</div>
</div>

<section></section>
```


Nothing too complicated here.... just a basic outline for the body. Inside that, I have a `p` and 2 `div`s with a `h1` and `img`. There's a section with the height of `100vh` below to give some scrolling space.

I'll use Sass for this tutorial but this can be done in CSS too. I'll add a link for the CSS version at the end of the post. I'm going to add some quick styling that is not at all related to scroll based animations.


```sass
// Unimportant and boring styling

body {
	background-color: #ffd9d1;
}

section {
	height: 100vh;
}

p {
	font-size: 1.5em;
	display: grid;
	text-transform: uppercase;
	letter-spacing: 1em;
	place-items: center;
	margin-top: 100px;
}

.inner {
	width: 60%;
}

.container {
	text-align: center;
	min-height: 80vh;
	display: grid;
	place-items: center;

	h1 {
		font-size: 3em;
		font-family: Poppins;
	}

	.image {
		height: 400px;
		background-size: cover;
		margin-top: 3em;
	}
}
```

I've just added some position, dimensions, fonts.... you get the idea. Not at all related to this demo. Let's get to the crux of the code. We'll create a very simple `pulse` keyframe animation that works with the scale of the image.

```sass
@keyframes demo {
	0% {
		border: 20px solid yellow;
	}

	25% {
		border: 20px solid green;
	}

	50% {
		border: 20px solid blue;
	}

	100% {
		border: 20px solid red;
	}
}
```

Nothing too complicated here.... just changing the border at various stages of the animation. I've chosen to go with borders because every time you change the position of the scrollbar the color changes and it's helpful to debug(I know its not good to animate border but I don't want to complicate things). Next, we have to create a timeline.

```sass
@scroll-timeline timeline {
	time-range: 1s;
}
```

We use the `@scroll-timeline` rule to make a timeline. I've called it `timeline`. Inside this, I've specified a `time-range` i.e. the amount of time I want to run the animation for. As we have defined our `animation-duration` to be 1s, we want our `time-range` to reflect that same duration. So, Scrolling from top to bottom (e.g. from 0% to 100%) should advance the animation by 1s. 


The `time-range` property is not the time of a clock. It is a mapping. This property is one of the most important properties in a `@scroll-timeline` rule. Let's make sure you understand this well by looking at some examples.

* `animation-duration` & `time-range` is `1 second`
As I said, `time-range` is a mapping. So, 0% of our keyframe maps to 0 seconds and 100% maps to 1 second. In this case, the animation will go from start to finish as the user scrolls from top to bottom

* `animation-duration` is `1s` & `time-range` is `2s`
This time around, 0% of our keyframe maps to 0 seconds and 100% maps to 2 second.

So, the animation will go twice as fast.

###Properties of a Timeline

A scroll timeline has some more properties -

1. `source`
2. `orientation`
3. `scroll-offsets`

We'll look at these as we go through the tutorial.

###Linking the Bits and Pieces

We need to link our `scroll-timeline`, `keyframe animation` with our object. Add the following properties to the object we want to animate.


```sass
#image {
	animation: 1s linear forwards demo;
	animation-timeline: pulse-timeline;
}
```

The first line is nothing new, just setting an animation for the object for it to repeat once for `1` second. The second line is where it gets interesting. I've specified an `animation-timeline` that links the timeline we made earlier.

  
From this, we can deduce that the three components for scroll based animations are:

1. An animation(eg keyframe)
2. A scroll timeline(eg pulse-timeline we just made)
3. The link(Linking animation with timeline)



### Scroll Offsets
If you run the code, the animation continues even after the object is out of the viewport. This is where the `scroll-offsets` property comes into the picture. The `scroll-property` takes 2 values i.e. the offset for the starting point and the offset for the end.

```sass
@scroll-timeline pulse-timeline {
	time-range: 1s;
	scroll-offsets: 0%, 100vh;
}
```


I haven't fiddled with the starting value as that works for us however I set the second value to `100vh` which means that it ends at `100vh`. If you notice, the animation speed has also slowed down that shows the mapping ratio has decreased.


### Scroll Orientation
By default a `scroll-timeline` will scroll from top to bottom i.e. vertical orientation. If we specify an orientation of horizontal, the animation will work during horizontal scrolling.


### Source
The source is scrollable element or container(default is body) whose scrolling triggers the activation of the animation and changes the timeline.



###The full demo 
{% codepen https://codepen.io/Akash123ak/pen/abBQYPE %}



### Conclusion
Normally for scroll linked animations I'd use GSAP/Intersection Observer along with ScrollMagic. Some parts of GSAP are not free and I feel that scroll magic has big learning curve(or the documentation isn't great). These also increase bundle size. 

It's great to see scroll based animations in CSS and I'm pretty certain this is going to be the way to go(once there's better support in browsers). 


That's it for now, hope you liked this post. If you did please like this post and follow me. Bye 👋