Make Your Website Content Flow Beautifully With This Simple JavaScript Technique

Roll with it: Easy engaging page scroll animations for React

Jonas Ohlsson Aden
Snips Blog

--

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.

The icons + labels here have reveal animations

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:

  1. Figure out when the content (the div) should be revealed
  2. (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! 💼

--

--

Jonas Ohlsson Aden
Snips Blog

Engineering Manager at Sonos inc. Passionate about the web, tooling and open source - let's make things better, for everyone!