darkroomengineering / lenis

How smooth scroll should be
https://lenis.darkroom.engineering
MIT License
7.37k stars 317 forks source link

HTML scroll behavior smooth - breaks lenis #217

Closed piscopancer closed 10 months ago

piscopancer commented 10 months ago

this style is good for article pages which enables smooth scrolling to a section when you click table of contents instead of teleporting

html {
  scroll-behavior: smooth;
}

this breaks lenis, sometimes you cannot scroll at all, sometimes it is super slow

Potential problem

with scroll behavior smooth you will notice that on the page load, if there is any # in the url, the browser smooth scroll will fire automatically and html will obrain lenis and lenis-smooth classes without your interaction. You did not even touch your mouse.

deepak-gangwar commented 10 months ago

Yes I checked, lenis is causing those issues when adding scroll-beharivor: smooth

Why are you not using the scrollTo() method? It works well with it.

Just pass in the CSS selector as the id of element to which you want to scroll to.

Great thing about using this technique is that you can specify the offset as well. The native scroll-behavior: smooth takes you to a position where the element is just touching the top of the viewport. But sometimes we don't want it at the very top, we want a little offset from top and lenis has that option.


Lenis suggests to Manually use lenis.scrollTo('#anchor') on anchor link click. See here.

Solution for your use-case 👇

For the links in your article you can do something like this:

function articleLinkScroll() {
        const headingLinks = document.querySelectorAll('[data-scroll-to]')
        headingLinks.forEach(link => {
            link.addEventListener('click', (e) => {
                e.preventDefault()
                const target = e.target.dataset.scrollTo

                // Use this if you want to define offset in your HTML (use data-scroll-offset attribute)
                // const offset = e.target.dataset.scrollOffset

                // or just define the offset in your javascript
                this.lenis.scrollTo(target, { offset: -window.innerWidth * 0.24 })
            })
        })
    }

You need to call this function when you initialize your smooth scroll. Remember to add the data-scroll-to="#anchor attribute to the anchor elements (in your case the table of content links).

For the time being, you can use this method. Let me see if there is something we can do with the native one. I hope it helps.

piscopancer commented 10 months ago

Well, what I described is absolutely a bug because smooth scroll behavior on html interrupts the scroll done by lenis. I understand, you need time to make out a way of fixing it. Thank you for a workaround, however I cannot use it in my Next app, because onclick is not permitted on SSR pages.

fix this bug please or if not possible to fix it, please explain why, I am interested in it too 💖

deepak-gangwar commented 10 months ago

In the docs of Lenis, they have asked to make sure scroll-behavior is set to auto or not set at all. I tried to look for a solution to your problem, but couldn't find one. Sorry.

I'm sure someone from the Lenis team can help or provide a clarification.

In the meantime, can you provide a minimal demo (codesandbox) of your SSR blog page if possible.

clementroche commented 10 months ago

scroll-behavior: smooth breaks Lenis, it's written in the documentation as @deepak-gangwar mentioned and there is nothing we can do about it.

One workaround using Next.js we used was:

  useEffect(() => {
    function onHashChangeStart(url) {
      url = '#' + url.split('#').pop()
      lenis.scrollTo(url)
    }

    Router.events.on('hashChangeStart', onHashChangeStart)

    return () => {
      Router.events.off('hashChangeStart', onHashChangeStart)
    }
  }, [lenis])

I know this doesn't work the exact same with app folder using Next.js but you can still listen to hash change.

maybe https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event or a specific next.js solution ?