Parallax like with Angular onscroll event

I tried to create a sort of parallax with Angular and OnScroll event, however when scrolling the text that appears is blinking. Do you know how to make the effect rendering smoother onscroll ? Maybe with CSS only ?

The script created https://stackblitz.com/edit/angular-b5cmf7?file=src%2Fapp%2Fapp.component.html

The main function that make the effect possible is this one

  @HostListener('window:scroll', ['$event'])
  isScrolledIntoView(){
    const offsetHeight = this.testDiv.nativeElement.children[0].offsetHeight; 
    const rect = this.testDiv.nativeElement.getBoundingClientRect();
    if( rect.bottom <= window.innerHeight){ // when the div is visible in viewport change the height (not more than the height of the content)
      let height = (window.innerHeight - rect.bottom);
      if(height<offsetHeight){
        this.height = height;
      }else{
        this.height = offsetHeight
      }
    }
  }

Solution 1:

As soon as I saw your blitz I recognised an issue I've run into many times. It's to do with how you calculate values on a per-frame basis. I'm not sure how best to put this in words, but it's something like this:

Don't base your calculations on values that will be modified by the result.

It's a bit abstract, but specifically in your case, the problem is with the relationship between rect.bot and this.height. With each call of your onscroll function, you modify the height of your section. But modifying the height will also modify the value of rect.bot, and on the next scroll event, you'll get a different result, so height gets modified from a different base, resulting in the oscillation you observed.

To avoid this, you want to base all your calculations only on values that are not affected by the result. In this case, I would recommend using rect.top, which doesn't care what the height of the section is.

Furthermore, I'd recommend using interpolation, because it gives you more control. The idea is you want to pick these values:

  • at what percentage of the window height should the reveal commence (effectively, this.height = 0)
  • At what percentage of the window height should the section be fully revealed (this.height = offsetHeight)
  • How should I interpolate between these two values? (easiest is linear)

So I've forked your blitz, and I've gone ahead and outright stolen the clamp and invlerp functions from here:

https://www.trysmudford.com/blog/linear-interpolation-functions/

You can read about these interpolation functions and their uses in that link.

you'll see I've made two variables called "startPercentage" and "endPercentage" – these are in relation to the value of rect.top as a percentage of window innerHeight. You can play around with these to get different speeds or qualities of parallax to get the effect of your liking.

Here's the fork:

https://stackblitz.com/edit/angular-lcyc4q?file=src%2Fapp%2Fapp.component.ts

And if you feel like it, look into other interpolation functions to experiment with ease-in and ease-out for different effects.