Its features were a bit basic though, limiting to “over N% of the viewport height once past D%”.
I mean, it works but leaves it all to the developer to figure out those percentages, which might vary from screen size to screen size as the responsive design puts the element in a different position… Not to mention the next change of design, introducing a new element higher up in the page and shifting the animated element down.
Let’s see if we can create something more expressive and resilient to design changes. When animating elements on scroll, percents of the viewport are not really the things we reason about first. It’s more natural to go for “start when the distance from the top of the element to the bottom of the viewport reaches S% of the ~screen~viewport height and until it reaches E%”. So let’s shoot for that.
- Values, like the top of the element, the bottom of the viewport or the viewport height. But those vary with time: the window can be resized, the user can scroll… So similarly to the sources of progress we have for the animations, we’ll need sources of values here.
- Computation over those values, like getting the distance between two points, or getting a percentage. Like a simple
/operator, except they’ll have to work with our sources of values we said we needed just above.
Bottom of viewport and viewport height
Let’s start with the simplest values here, which are actually the same value if you think about it. From the top of the viewport (which we’ll use as a common origin for our coordinates), they are the same value. And we don’t even need any computation to get it, the DOM provides it straight away:
The main thing we need to handle is making sure we can observe the changes of this value when the screen is resized.
Top of el
Now we’ve got our information about the viewport, let’s get those about the element. That’s the one that’ll actually trigger changes on scroll, as the position of the element relative to the top of the viewport will change then.
Here again, the DOM is pretty handdy providing that, with
And with that, we’re ready to move on to computing the distance and percentage.
As the values above change, so will the distance and percentage. This means they also need to be sources of values. Sources of value that will:
- combine the value from different sources
- compute a new value from there
Combine, first. When observed, it’ll need to observe the sources it combines and just provide their values in an array.
From there we can create the final sources, consuming this array for computation, but only after all data is there:
Tying it all together
There we go! We have everything we need and can now write a more understandable:
percentOf(viewportHeight, distance(topOf(el), bottomOfViewport)) to use as our source of progress. As it is, it would animate as the element goes through the whole viewport. We just need one last wrapping source that will scale the percentage into a neat [0..1] range according to our wishes. Let’s call it
And voila! Combining functions, we have a pretty expressive way to define scroll based animations.
As with the first article, this is just a base to start with, that I got from implementing scroll based animations on this website. There’d be plenty more to explore around those scroll sources like :
– providing some based on the
– handling conditions different landmarks on the element & viewport (for example: start when the top of the element crosses the bottom of the viewport and end when its bottom crosses the top of the viewport…)
And of course around the areas for making animations with functions. I’ve started to gather some code on the tinymation project on Github. If you have thoughts on the topic, maybe specific use case, I’d be really happy to head about them. Feel free to look at the code and add issues (or comment on the existing ones).