🛠️ Slide & Reveal: Always fade-in when you scroll down

Hey ,

I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.

Please upgrade (use this link) access this content.

I'm super eager to help you learn more!

🛠️ Slide & Reveal: Always fade-in when you scroll down

If you paid attention to some well-designed sites, you’ll notice that, if they fade in an element, they’ll always fade in that element when you scroll down.

Here’s an example where Apple fades in a block of text.

We can create this effect easily with Intersection Observer.

Making an element fade in again

If we want an element fade in again, we need to remove the is-visible class when the element goes outside of the screen.

We know the element is outside of the screen if entry.isIntersecting is false.

const callback = entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('is-visible')
    } else {
      // Element is outside the screen.
      entry.target.classList.remove('is-visible')
    }
  })
}

Only fade in elements when scrolling down

Try scrolling upwards now. You’ll notice elements above the viewport fade in as well. This happens because we removed is-visible for all elements that are outside of the viewport (which includes the ones at the top).

This is undesirable.

When you scroll past an element on a website, you expect that element to be visible. If we add fade elements in from the top, we’re going against this expectation.

On the other hand, you don’t expect elements below your viewport to be visible until they appear. We can always fade elements in from the bottom to create delight.

This means we want to remove is-visible only if the element becomes invisible by going below the viewport.

Fortunately, this is easy.

We can use boundingClientRect to tell the location of the observed element. If the top value from boundingClientRect is negative, we know the element is above the viewport.

This means we know the element went below the viewport if:

  1. entry.isIntersecting is false
  2. entry.boundingClientRect.top is larger than 0.
const callback = entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('is-visible')
    }

    if (!entry.isIntersecting && entry.boundingClientRect.top > 0) {
      entry.target.classList.remove('is-visible')
    }
  })
}