Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seemingly incompatible with smooth-scroll libraries #229

Open
StevenStavrakis opened this issue Apr 26, 2021 · 6 comments
Open

Seemingly incompatible with smooth-scroll libraries #229

StevenStavrakis opened this issue Apr 26, 2021 · 6 comments

Comments

@StevenStavrakis
Copy link

Due to the way that I understand Rellax calculates the parallax effect, it cannot be used in conjunction with a smooth scroll library.

@StevenStavrakis StevenStavrakis changed the title Seeminly incompatible with smooth-scroll libraries Seemingly incompatible with smooth-scroll libraries Apr 26, 2021
@StevenStavrakis
Copy link
Author

I've found a hacky fix. Many scroll-jacking libraries will provide a property on the smoothScroll object which gives the estimated scroll position. By adding some JS to create two divs, one a container the height and width of the view with overflow scroll, the other inside it made to be the height of the page content, and programmatically setting the containers scroll position with what the smooth scroll library provides on every frame (using requestAnimationFrame), I can then point the Rellax wrapper at that element and hide it behind everything.

There are still some issues I haven't figured out, mostly GSAP animations doing weird things, but it somewhat works.

It would be much, much easier if rellax had an option to just pass a scroll position to it instead.

@cleuenberg
Copy link

Hi @StevenStavrakis , I am currently trying to "smooth" the horizontal scrolling with some libraries, but with no success. Could you please provide an example of your attempt? That would be really great! And yes, I would also like to see rellax handling this issue out-of-the-box.

@StevenStavrakis
Copy link
Author

StevenStavrakis commented Apr 30, 2021

@cleuenberg

I can't say I know how to work with it horizontally, but I imagine my solution can be made to work with whatever case is needed.

That being said, this was done for a full page smooth scroll. Outside that I can't guarantee it will work. I also found it doesn't play nice with gsap animations and I haven't found a solution for that yet.

For my solution I used ASScroll, Ash's Smooth Scroll Library. The ASScroll object provides a smoothScrollPos property on every frame which represents the simulated scroll position of the smooth-scroll container.

When initializing Rellax, you can give it a custom wrapper to look at and get the scroll position from. Since we are unable to feed a scroll position straight into the Rellax configuration, it occurred to me that the only way for them to work together would be to create two DOM elements, a container the size of the viewport, and a div the height of the document, and using ASScroll's requestAnimationFrame loop, manually update the new elements scroll position to match the smoothScrollPos property provided each frame. With that, you can configure Rellax to look at the newly created scrollcontainer to conduct its parallax.

The resulting code:

 import ASScroll from "https://cdn.skypack.dev/@ashthornton/[email protected]";
    
    // Initialize smooth scrolling on your desired container
    // This is your "actual" scroll container
    const smoothScroll = new ASScroll({element: '.smooth-scroll'});
    
    // Create a fake scroll container which Rellax will observe for scroll position
    const scrollTrackerContainer = document.createElement('div');
    scrollTrackerContainer.classList.add('scroll-tracker-container');
    
    // Make it fill the viewport (same as the actual scroll container)
    scrollTrackerContainer.style.width = "100vw";
    scrollTrackerContainer.style.height= "100vh";
    scrollTrackerContainer.style.position = "fixed";
    scrollTrackerContainer.style.top = "0";
    scrollTrackerContainer.style.left = "0";
    
    // Put it behind everything, make sure it can't be interacted with, and hide it
    scrollTrackerContainer.style.zIndex = "-1";
    scrollTrackerContainer.style.pointerEvents = "none";
    scrollTrackerContainer.style.visibility = "hidden";
    
    // Make sure it can scroll
    scrollTrackerContainer.style.overflowY = "scroll";
    
    // Add it to body (or wherever your actual scroll container is)
    document.body.appendChild(scrollTrackerContainer);
    
    // Create the inner element and append it to the scrollTrackerContainer
    const scrollTracker = document.createElement('div');
    scrollTracker.classList.add("scroll-tracker");
    scrollTrackerContainer.appendChild(scrollTracker);
    
    // Every frame, set the scroll position of the scrollTrackerContainer to be the value provided by
    // ASScroll
    smoothScroll.on('raf', ({ scrollPos, smoothScrollPos }) => {
        scrollTrackerContainer.scrollTop = Math.abs(smoothScrollPos);
    });
    
    // When the window loads, enable smoothScroll and set the inner scrollTracker element to the height of
    // your scroll container, in this case, the body
    window.addEventListener("load", () => {
        smoothScroll.enable()
        scrollTracker.style.height = document.body.clientHeight + "px";
    });

And now we can initialize Rellax

window.addEventListener("load", () => {
  let rellax = new Rellax('.rellax', {
    wrapper: '.scroll-tracker-container'
});  
});

Aside from the problems with gsap, which is something I need to solve or else this solution won't work for me, this seems to work great. I imagine with a bit of tinkering it could be made to work easily with any particular use case.

One last consideration:

This solution doesn't update the artificial scrollheight fractionally because, well, I don't know how to and I haven't looked into it. What this means is that there is a barely, barely noticeable jitter compared to the smooth scroll when scrolling since it's being updated as integers instead of floats.

@licentiapoetica
Copy link

I am experiencing a similar problem while using fullpage.js, it's not compatible, very sad

@StevenStavrakis
Copy link
Author

@ottersarecool

I've never used fullpage.js, however I think that the solution I provided above can be adapted to it. These scroll libraries usually take the native scroll and translate it into a "virtual" scroll. My method creates an invisible element for rellax to look at and re-applies the native scroll to it.

Looking at fullpage.js, I don't see a super easy way of doing it like I did in my solution, but so long as you can track the virtual scroll position it should work.

That being said, looking over the fullpage.js documentation, I cannot recommend using it. The features seem seriously limited for something that developer need to pay for.

Overall, I have begun moving away from libraries entirely and instead manually create solutions using GSAP. It has a much higher learning curve, but it allows me to come up with the best solutions on the fly. With it, you can create the smooth scrolling effect you are looking for, but also create the parallax effect from rellax, all without extra libraries. I have only been pleased by its efficacy since I started using it.

@licentiapoetica
Copy link

@ottersarecool

I've never used fullpage.js, however I think that the solution I provided above can be adapted to it. These scroll libraries usually take the native scroll and translate it into a "virtual" scroll. My method creates an invisible element for rellax to look at and re-applies the native scroll to it.

Looking at fullpage.js, I don't see a super easy way of doing it like I did in my solution, but so long as you can track the virtual scroll position it should work.

That being said, looking over the fullpage.js documentation, I cannot recommend using it. The features seem seriously limited for something that developer need to pay for.

Overall, I have begun moving away from libraries entirely and instead manually create solutions using GSAP. It has a much higher learning curve, but it allows me to come up with the best solutions on the fly. With it, you can create the smooth scrolling effect you are looking for, but also create the parallax effect from rellax, all without extra libraries. I have only been pleased by its efficacy since I started using it.

Yes I ended up doing my project without it in favor of rellax, was the better choice, but thank you for your answer!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants