Jump to content
Search Community

Issue with Scroll Position Resetting After Programmatic Scroll in GSAP

chillypills test
Moderator Tag

Recommended Posts

Hello everyone,

 

I'm currently facing an issue on a website that features a horizontally scrolling section. I've set up the site so that when a user clicks on a year from a menu, the page correctly scrolls to the corresponding element in the horizontal scroll section. However, after this scroll occurs and the target is reached, if the user attempts to manually scroll again, the scroll position automatically jumps back to where it was before the menu item was clicked.

 

Here is a brief overview of the technologies and setup:

  • JavaScript Libraries: I'm using GSAP for animations, with plugins like ScrollToPlugin and ScrollTrigger. Additionally, I'm integrating Swiper for swipe functionalities and Lenis for smooth scrolling effects.
  • Behavior: Upon clicking a year in the menu, GSAP's ScrollToPlugin does its job to bring the target element into view. After reaching the target, any new user-initiated scroll action causes the page to revert to the original scroll position.
  • Expected Behavior: The scroll position should remain at the new location after scrolling to the target, and any further manual scrolling should be based on this new position.

I suspect there might be an issue with how the scroll position state is managed after a programmatic scroll, or perhaps there's a conflict between GSAP's scroll handling and Lenis's smooth scrolling. I've tried managing the update cycles of Lenis and ensuring the GSAP animations are synchronized with it, but the issue persists. I have also experimented with using flags and various methods to lock the scroll position temporarily, but nothing has resolved the issue so far.

 

I'm doing it in Webflow so you can see the problem here: https://las-vidas-que-nos-dejaron.webflow.io/

// GSAP HORIZONTAL SCROLL LOGIC
  let isScrollingToYear = false // Add this line at the beginning of your script

  let horizontalItem = $('.horizontal-item')
  let horizontalSection = $('.horizontal-section')
  let moveDistance

  // Declare a variable to store the last scroll position
  // eslint-disable-next-line no-unused-vars
  let lastScrollPosition = 0

  function calculateScroll() {
    // Desktop
    let itemsInView = 4
    let scrollSpeed = 3

    if (window.matchMedia('(max-width: 479px)').matches) {
      // Mobile Portrait
      itemsInView = 1
      scrollSpeed = 1.2
    } else if (window.matchMedia('(max-width: 767px)').matches) {
      // Mobile Landscape
      itemsInView = 1
      scrollSpeed = 1.2
    } else if (window.matchMedia('(max-width: 991px)').matches) {
      // Tablet
      itemsInView = 2
      scrollSpeed = 1.2
    }
    let moveAmount = horizontalItem.length - itemsInView
    let minHeight =
      scrollSpeed * horizontalItem.outerWidth() * horizontalItem.length
    if (moveAmount <= 0) {
      moveAmount = 0
      minHeight = 0
      // horizontalSection.css('height', '100vh');
    } else {
      horizontalSection.css('height', '200vh')
    }
    moveDistance = horizontalItem.outerWidth() * moveAmount
    horizontalSection.css('min-height', minHeight + 'px')
  }
  calculateScroll()
  window.onresize = function () {
    calculateScroll()
  }

  let tl = gsap.timeline({
    scrollTrigger: {
      trigger: '.horizontal-trigger',
      start: 'top top',
      end: 'bottom top',
      markers: false,
      invalidateOnRefresh: true,
      scrub: 1,
    },
  })

  tl.to('.horizontal-section .list', {
    x: () => -moveDistance,
    duration: 1,
  })

And function to scroll to the element with the given year and month ID (years menu)
 

 // Function to scroll to the element with the given year and month ID
  function scrollToYear(year, month) {
    const targetId = `#year-${year}-${month}`
    const targetElement = $(targetId)

    if (targetElement.length) {
      // Set the flag to true
      isScrollingToYear = true
      console.log('Is scrolling to year enabled?', isScrollingToYear)

      // Calculate the target scroll position
      const scrollX = targetElement.position().left
      console.log('Target scroll position:', scrollX)

      // Log the current scroll position
      console.log(
        'Current scroll position:',
        $('.horizontal-section .list').position().left
      )

      // Save the current scroll position
      lastScrollPosition = $('.horizontal-section .list').position().left

      // Animate the horizontal scroll to the target element's X position
      gsap.to('.horizontal-section .list', {
        x: () => -scrollX,
        duration: 3,
        ease: 'power3.inOut',
        onUpdate: Lenis.update, // Assuming lenis.update is the method that needs to be called on update
        onComplete: () => {
          console.log(
            `Smoothly scrolled to the year: ${year} and month: ${month}`
          )

          // Remove --is-active class from any other elements that might have it
          $('.horizontal-section .list .--is-active').removeClass('--is-active')
          $('.horizontal-month-item.--is-active').removeClass('--is-active')

          // Add --is-active class to the target element
          targetElement.addClass('--is-active')

          // Format the month to have two digits
          const formattedMonth = month.toString().padStart(2, '0')

          // Find the corresponding .horizontal-month-item and add the --is-active class
          const targetMonthItem = $(
            `.horizontal-month-item[data-month="${formattedMonth}/${year}"]`
          )
          if (targetMonthItem.length) {
            targetMonthItem.addClass('--is-active')
          }

          // Update the sticky title
          gsap.to('.sticky_title', {
            duration: 0.2,
            autoAlpha: 0,
            onComplete: function () {
              $('.sticky_title').text(year)
              gsap.to('.sticky_title', { duration: 1.5, autoAlpha: 1 })

              // Log the current scroll position after the animation
              console.log(
                'Current scroll position after animation:',
                $('.horizontal-section .list').position().left
              )

              // Set the flag back to false
              isScrollingToYear = false
              console.log('isScrollingToYear enabled?', isScrollingToYear)

              // Update the move distance directly
              moveDistance = -$('.horizontal-section .list').position().left
            },
          })
        },
      })
    } else {
      alert(`No element found with ID: ${targetId}`)
      console.error(`No element found with ID: ${targetId}`)
    }
  }

 

Link to comment
Share on other sites

Yeah, that doesn't look like it's GSAP-related at all. GSAP seems to be doing its job, but from what I can tell, you've got some other library or logic that's implementing a fake scrollbar and it's not getting updated properly when the window is scrolled to the appropriate position. I'd recommend looking at that library to figure out what it's doing (or not doing). Maybe there's some kind of update method you need to call from within an onUpdate on the scrollTo tween to get it to update that fake scrollbar to the correct position. 

 

We can't really do much if you don't provide a minimal demo (like a CodePen or Stackblitz) or if it's not a GSAP-related issue. Hopefully this gets you going in the right direction though. 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...