Make Your Website Content Flow Beautifully With This Simple JavaScript Technique
Roll with it: Easy engaging page scroll animations for React
At Snips, we work with Voice and AI to make technology disappear. In our web presence we make good use of scrolling animations and similar effects, to make for a more engaging experience for our users. After we launched our well received 6 minute intro to AI microsite, we started getting questions about the tech we used for the scroll effects, cue this post. Read on for a more in-depth technical guide on how we set up our reveal animations, or jump straight to the end if you just want to see how you can get the same effects into your own projects today!
Reveal animations
Let’s start with what is sometimes called reveal animations, where content gets animated in as it’s scrolled into view.
For this we we’re looking for something as simple to use as the wow reveal js library , but that we could use in Reacts code paradigm. We wanted to be able to declaratively setup animations in the middle of the code, clearly connected to the content to be revealed. Something like this:
// in the middle of a render function..
<InViewMonitor>
<div>some content to be revealed here</div>
</InViewMonitor>
We need to do two things:
- Figure out when the content (the
div
) should be revealed - (hide and) reveal it
In view detection in JavaScript
(Soon we will be able to delegate this to the IntersectionObserver API)
First we need to know where on the page the content is, in terms of offset to the first pixel in the y dimension. Unfortunately there’s no single API in JS for determining this, as theoffsetTo
on DOM Elements just gives the relative offset to its parent, not to the page. We can use the offsetParent
property to traverse the DOM tree to manually sum the offset compared to the page:
Now getElementOffset(element).top
gives us the number of pixels we need to scroll from the top of the page until the top of the element is at the top of the screen. But we want to start revealing the element when it is just about to enter the screen, from the bottom, so we need to offset the window height:
const elementOffsetTop = getElementOffset(DOMElement).top
const scrollIntoViewThreshold =
elementOffsetTop -
window.innerHeight
We might further want to tweak when to reveal the element, say by waiting until 20% of it has turned up in the viewport. For this we would use the getBoundingClientRect
native DOM element method:
const elementHeight = DOMElement.getBoundingClientRect().height
const scrollIntoViewThreshold =
elementOffsetTop -
window.innerHeight +
elementHeight * 0.2
Now we know the exact pixel value at which we want to start of reveal animations (scrollIntoViewThreshold
). We just need to compare the current scroll position to this value:
if (window.pageYOffset > scrollIntoViewThreshold) {
// we have been scrolled into (or past) view!
}
Comparing positions on scroll
While we can cache the scrollIntoViewThreshold
value (as long as the position of the element on the page doesn’t change), to perform a reveal animation after the user has scrolled the element into view we need to continuously check the updatedwindow.pageYOffset
— on scroll.
Hiding and revealing
There are multiple ways this could be done, but for us it made perfect sense to mimic what the wow reveal js library does and just do some simple class switching, which we setup as React props to our component:
<InViewMonitor
classNameInitial="vis-hidden"
classNameOnScrollIntoView="animate fadeInUp"
>
<div>some content here</div>
</InViewMonitor>
Then we simply put className: props.classNameInitial
in the component state when the component is mounting, which we replace with the classNameOnScrollIntoView
value when it gets scrolled in to view, as we discussed above.
.vis-hidden
can be as simple as visibility: hidden;
and for the animate
and fadeInUp
classes we get from the awesome Animate.css mini animation library, but you can of course provide your own as you like.
All-right, still with me? Great! Now while writing this code above is not too complex, it’s still time consuming.. But we have good surprise for you:
🎉 Now open source for you to use! 🎉
The InViewMonitor
React component is now available, and you can get it set up in your project a matter of minutes. Check out the code and more examples on Github:
In addition we also open sourced a ScrollingColorBackround
React component, which does what it says on the box:
We’re have more exciting projects coming up that will use these two components, and we hope that they’ll be useful for you as well!
Snips is committed to open source as part of privacy-by-design and transparency ethos, so watch this space as we plan to open source more code (not just JavaScript) in the future!
Final note if you would like to work on things like this— we’re hiring! 💼