jlmakes / scrollreveal

Animate elements as they scroll into view.
https://scrollrevealjs.org/
22.39k stars 2.26k forks source link

using intersection observer api #381

Closed Mohsen-Khakbiz closed 7 years ago

Mohsen-Khakbiz commented 7 years ago

is there anyway to use intersection observer api for this plugin? you know for better performance. as there's a polyfill for IO there's no concern about browser compatibility in my case. or if you could guide me how to achieve it, it'll be much appreciated.

Regards, Mohsen

jlmakes commented 7 years ago

Thanks for asking Mohsen.

Performance

I’m not aware of any performance issues with ScrollReveal; in fact, the only issue I can recall was related to layout reflow, and it was improved significantly in ScrollReveal 4 (beta).

Other improvements include caching all element dimensions and position, further lightening the burden on event handlers. Even though it’s in beta (for only a few more weeks), version 4 is the most stable and robust version to date—I strongly recommend upgrading.

<script src="https://cdn.jsdelivr.net/npm/scrollreveal@beta"></script>

See What’s New in 4.0.

Intersection Observer

It’s important to know that Intersection Observer will include CSS Transforms in its logic—which actually complicates using them for reveal on scroll libraries, particularly ScrollReveal. Let’s go through an example to explain why.

I know IntersectionObserver doesn’t return coordinates, but the idea behind this example still applies. Please bear with me.

Imagine we have an Element at coordinates (2, 1) on our page:

screen shot 2017-10-11 at 4 52 53 pm

ScrollReveal (and I presume other reveal on scroll libraries) will use CSS Transform to create animations. Let’s say we’ve added some translateX to our Element because we’re planning to reveal it from the right side of the window.

screen shot 2017-10-11 at 4 53 01 pm

What would we expect/want the coordinates of our Element to be?

This is where we see the critical difference between using offsetLeft and offsetTop to determine element visibility (the technique used by ScrollReveal), and using modern browser APIs such as IntersectionObserver or getBoundingClientRect.

If we use the newer APIs, they will include the CSS Transform and we’d get (9, 1):

screen shot 2017-10-11 at 5 02 12 pm

Whereas, if we use offset values, we’ll still get the original coordinates (2, 1):

screen shot 2017-10-11 at 5 07 43 pm

Why This Matters

Well, is the Element (9, 1) within the window's range of {8, 5}?

No. It’s not within the window (which is easily seen in the figure). In fact, this element would never be considered "visible" (without some form of horizontal scrolling), but herein lies the problem.

We don’t really care where the element is in its pre-reveal state... rather, we want to know "if we revealed this element now, would it be visible after the animation completes?"

It sounds like a good thing that modern APIs include our CSS Transform, and indeed for many use cases I’m sure it is... but by obscuring the element’s original/post-reveal position, it actually makes it significantly more difficult to determine whether our Element should be revealed.

I actually tried to use getBoundingClientRect at one point, and elements would constantly bounce in and out of view because the position coordinates were constantly changing during animation.

Now, IntersectionObserver uses percentages (something called Intersection Ratios), not coordinates, but the problem is the same: The position reported by IntersectionObserver is influenced by CSS Transform.

So, Offsets Forever?

Well, because offset values ignore CSS transforms, we can trust that when we check an element’s position, we will be checking the "post-reveal" position we care about... not the rendered position of the element.

I’m sure a clever developer could build a reveal on scroll library from scratch that leverages getBoundingClientRect or IntersectionObserver, but ScrollReveal has a pretty substantial feature base with very wide browser support—and relying on offset values works quite well.

tl;dr

I wouldn’t recommend trying to replace the element visibility logic with IntersectionObserver(or getBoundingClientRect for that matter). If you’re concerned about performance, consider upgrading to ScrollReveal 4 (beta).