Jump to content
Search Community

Video scroll animation lagging

vierless_julian test
Moderator Tag

Recommended Posts

Hey guys, I need your help!

We are working on our new page and I am trying to get an scroll animation to work. I have a video on the top of the page that I want to transform on scroll. At the same time a background image is blurred. I tried getting it to work with Webflow interactions but the scroll triggers confused me too much.

The animation is loading fine but it feels a little laggy. Especially in Chrome. Safari works fine. Also Arc which is based on Chrome works fine.

Could someone look into that?
This is our page: https://cf-vierless.webflow.io

This is my code:
 

document.addEventListener("DOMContentLoaded", function() {
  const videoContainer = document.querySelector(".hero-vertical_video");
  const background = document.querySelector(".hero-vertical_image");

  // Function to calculate element offsets
  const calculateOffsets = () => {
    videoContainerOffset = window.pageYOffset + videoContainer.getBoundingClientRect().top;
    backgroundOffset = window.pageYOffset + background.getBoundingClientRect().top;
  };

  // Initial offset calculation
  let videoContainerOffset, backgroundOffset;
  calculateOffsets();

  // GSAP animation
  gsap.registerPlugin(ScrollTrigger);

  gsap.fromTo(".hero-vertical_video", {
    x: "28%",
    y: "37%",
    z: "0",
    skewX: "0deg",
    skewY: "8deg",
    scaleX: 1,
    scaleY: 1,
    rotation: 0,
    perspective: 0
  }, {
    x: "50%",
    y: "37%",
    z: "0",
    skewX: "0deg",
    skewY: "0deg",
    scaleX: 1.4,
    scaleY: 1.4,
    rotation: 0,
    perspective: 0,
    duration: 1,
    ease: "power4.out",
    scrollTrigger: {
      trigger: ".hero-vertical_video",
      onUpdate: calculateOffsets,
      start: () => "top " + videoContainerOffset + "px",
      end: "top 10%",
      scrub: 0.75,
      toggleActions: "restart none none none"
    }
  });

  gsap.to(".hero-vertical_image", {
    filter: "blur(40px)",
    scaleX: 0.75,
    scaleY: 0.75,
    duration: 1,
    ease: "power4.out",
    scrollTrigger: {
      trigger: ".hero-vertical_video",
      onUpdate: calculateOffsets,
      start: () => "top " + backgroundOffset + "px",
      end: "top 10%",
      scrub: 1.5,
      toggleActions: "restart none none none"
    }
  });

  // Recalculate offsets on screen resize
  window.addEventListener("resize", () => {
    calculateOffsets();
  });
});

 

Link to comment
Share on other sites

A few things: 

  1. Why are you calculating the offsets on every single update of the ScrollTrigger? That seems very wasteful. 
    onUpdate: calculateOffsets, // <-- remove this?

    Maybe you intended that to run onRefreshInit or onRefresh? 

  2. You can't have scrub and toggleActions - those are mutually exclusive. You can remove the toggleActions if you have a scrub. 
  3. There's no point in having rotation, perspective, or skewX in your tween because you're not animating those at all. 
  4. Filters are TERRIBLE for performance, just so you know. It's totally unrelated to GSAP. It's just that browsers have a tough time rendering them. You might want to try adding will-change: transform on anything you're animating (I saw you only had it set to filter on that image). One trick is to create a blurred version of the image (like in Photoshop), and then just crossfade that blurred version with the non-blurred version. That'll be WAY cheaper for the browser to render. 
  • Like 1
Link to comment
Share on other sites

Hi @GreenSock!

Thank you very much for your help! I am still not very experienced with GSAP and kind of stumbled my way to this working solution. Now I am making adjustments based on your recommendations.

About the onUpdate:
I was trying to take into account that the position of the video changes in the DOM depending on the text wrapping since this changes the height and therefore the distance to the top of the page. Also I wanted to change a value (the scale) when on mobile devices and this should update when resizing the browser.

Your point 4 is interesting!
I was thinking about a solution that animates opacity of an overlay for that image from 0 to 100%. The overlay could have the backdrop-filter property and blur the image behind the overlay. Do you think this solution could work and how do you think about performance in that case? Also do you have a working example for the blurred image solution you are referring to? I'd love to explore this and try it out myself.

Link to comment
Share on other sites

Update:
This is my new code:

 

document.addEventListener("DOMContentLoaded", function() {
    const videoContainer = document.querySelector(".hero-vertical_video");
    const background = document.querySelector(".hero-vertical_image");

    // Function to calculate element offsets
    const calculateOffsets = () => {
      videoContainerOffset = window.pageYOffset + videoContainer.getBoundingClientRect().top;
      backgroundOffset = window.pageYOffset + background.getBoundingClientRect().top;
    };

    // Initial offset calculation
    let videoContainerOffset, backgroundOffset;
    calculateOffsets();

    // GSAP animation
    gsap.registerPlugin(ScrollTrigger);

    // Determine the scale value based on the device's characteristics
    const scaleValue = window.innerWidth < 992 ? 1.8 : 1.4;

    gsap.to(".hero-vertical_video", {
      x: "50%",
      y: "37%",
      // z: "0",
      skewX: "0deg",
      skewY: "0deg",
      scaleX: scaleValue, // Use the determined scale value
      scaleY: scaleValue, // Use the determined scale value
      rotation: 0,
      // perspective: 0,
      duration: 1,
      ease: "power4.out",
      scrollTrigger: {
        trigger: ".hero-vertical_video",
        // onUpdate: calculateOffsets,
        start: () => "top " + videoContainerOffset + "px",
        end: "top 10%",
        scrub: 0.75,
        // toggleActions: "restart none none none"
      }
    });

    gsap.to(".hero-vertical_image", {
      // filter: "blur(40px)",
      scaleX: 0.75,
      scaleY: 0.75,
      duration: 1,
      ease: "power4.out",
      scrollTrigger: {
        trigger: ".hero-vertical_video",
        // onUpdate: calculateOffsets,
        start: () => "top " + backgroundOffset + "px",
        end: "top 10%",
        scrub: 1,
        // toggleActions: "restart none none none"
      }
    });

    // Recalculate offsets on screen resize
    window.addEventListener("resize", () => {
      calculateOffsets();
    });
  });

If I comment the rotation and the skewX out, I get strange results. Suddenly the rotation is set to 8deg or something else is wrong, so I kept it in.

Link to comment
Share on other sites

Hi,

 

There is no need to use scaleX and scaleY if you're using the same value, just use:

// First
scale: scaleValue
// Second
scale: 0.75

Also there is no need to pass the unit to skew, just pass 0:

skewX: 0,
skewY: 0,

Also I'm guessing that you're setting the initial values for skew using CSS, right? Better let GSAP handle all transforms for you, so at the top of your code just add this:

gsap.to(".hero-vertical_video", {
  skewX: 8,
  skewY: 8,
});

Hopefully this helps. If you keep having issues please create a minimal demo that we can have a look at.

Happy Tweening!

Link to comment
Share on other sites

2 hours ago, vierless_julian said:

I am still not very experienced with GSAP and kind of stumbled my way to this working solution.

No problem! This is the place to come when you have a question. It's totally fine that you're new to GSAP and trying to learn. Welcome!

 

2 hours ago, vierless_julian said:

Also I wanted to change a value (the scale) when on mobile devices and this should update when resizing the browser.

ScrollTrigger automatically handles resize events (and throttles them for performance). If you want a different animation for mobile devices, you might want to check out gsap.matchMedia()

 

Instead of setting up your own "resize" handler where you keep doing the calculations on every resize, I'd recommend using a function-based value that calculates it only when you need it, like: 

const getVideoContainerOffset = () => window.pageYOffset + videoContainer.getBoundingClientRect().top;

// in your ScrollTrigger:
start: () => "top " + getVideoContainerOffset() + "px",

 

2 hours ago, vierless_julian said:

I was thinking about a solution that animates opacity of an overlay for that image from 0 to 100%. The overlay could have the backdrop-filter property and blur the image behind the overlay. Do you think this solution could work and how do you think about performance in that case? Also do you have a working example for the blurred image solution you are referring to? I'd love to explore this and try it out myself.

No, I would not have a backdrop-filter. I'm saying you literally create a copy of the image that is blurred in something like Photoshop (or whatever), and save that as an image and place it directly on top or behind the normal image and then cross-fade them to make it look as if the normal image is becoming blurry (but it's just a crossfade - nothing is happening with filters). The entire goal here is to save the browser from having to do all the blurring calculations. I don't have an example off the top of my head to show you, but hopefully the concept is very simple to grasp and you can give it a shot. 

2 hours ago, vierless_julian said:

If I comment the rotation and the skewX out, I get strange results. Suddenly the rotation is set to 8deg or something else is wrong, so I kept it in.

My guess is that you had a transform applied via CSS and that was getting parsed in as such. So it's fine to set that value in the "from" part of the tween, or initially using a .set(). 

 

It's difficult to offer advice when we don't have a minimal demo (CodePen or Stackblitz) to look at. One of those will go a long way toward getting you solid help. 

 

Good luck!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...