Jump to content
GreenSock

Samuele

Horizontal scroll Anchors section

Go to solution Solved by akapowl,

Recommended Posts

Hi there!

Is it possible to add an anchor menu navigation that linked to the several section of the website? (one / two / three and so on..)?
Based on this Codepen: 

I started using the href tag with the "#{namesection}" and addEventListener("click") scrollIntoView() but it didn't work.

 

See the Pen YzygYvM by GreenSock (@GreenSock) on CodePen

Link to comment
Share on other sites

Hi Samuele,

 

scrollIntoView won't work because the horizontal scrolling is of course fake. You would need to use the ScrollToPlugin and calculate the scroll position for the horizontal section you are targeting, kind of like in this demo...

 

See the Pen bGexQpq by GreenSock (@GreenSock) on CodePen

 

  • Like 1
Link to comment
Share on other sites

Hi there, thanks for your help.
As you suggested I'm trying to understand how to calculate the scroll position for the horizontal section.

I created a new cpen:

See the Pen oNGNXRB by sml-k (@sml-k) on CodePen



This is how I declare the horizontal scroll (whereas by drag or scroll):

 //Scroll and drag
  ScrollTrigger.matchMedia({
    "(min-width: 1080px)": () => {
      let scrollTween = gsap.to(sections, {
        x: () =>
        -(scrollContainer.scrollWidth - document.documentElement.clientWidth) + "px",
        ease: "none",
        scrollTrigger: {
          trigger: scrollContainer,
          invalidateOnRefresh: true, //check
          pin: true,
          scrub: 1,
          end: () => "+=" + scrollContainer.offsetWidth,
        },
      });

      var dragRatio =
        scrollContainer.offsetWidth /
        (window.innerWidth * (sections.length - 1));
      var drag = Draggable.create(".proxy", {
        trigger: scrollContainer,
        type: "x",
        onPress() {
          this.startScroll = scrollTween.scrollTrigger.scroll();
        },
        onDrag() {
          scrollTween.scrollTrigger.scroll(
            this.startScroll - (this.x - this.startX) * dragRatio
          );
        },
      })[0];

      return () => {
        scrollTween.kill();
        drag.kill();
      };
    },
  });


I think that the correct process would be define all the anchors, add an addEventListener and then run some function?
I didn't quite catch how to create and calculate the section's width and then run a scroll animation, could you help me? (for newby sake)

Link to comment
Share on other sites

Can you simplify your codepen? Let's just focus on one thing at time, so get rid of all the media query CSS, matchMedia, and Draggable stuff.

Link to comment
Share on other sites

Sure! I just edited my code.
So i just keep the ScrollTween part and simplify the style:
 

  //horizontal scroll
  let scrollTween = gsap.to(sections, {
    x: () =>
      -(scrollContainer.scrollWidth - document.documentElement.clientWidth) +
      "px",
    ease: "none",
    scrollTrigger: {
      trigger: scrollContainer,
      invalidateOnRefresh: true,
      pin: true,
      scrub: 1,
      end: () => "+=" + scrollContainer.offsetWidth,
    },
  });

  return () => {
    scrollTween.kill();
    drag.kill();
  };


See the Pen oNGNXRB by sml-k (@sml-k) on CodePen

Link to comment
Share on other sites

Hi @Samuele

 

I'm a little confused about where exactly you are expecting those panels to line up. For example, if you want to go to slide 2, is it supposed to line up with nav.

 

image.png

 

If so, that couldn't work for the 4th slide because it doesn't reach the nav. This is as far left as it goes.
 

image.png

 

 

 

Link to comment
Share on other sites

You're right!
I'm expecting that the panel will be lined up to the navbar. 

A perfect scenario is what you've attached above.
The panel will scroll and "snap" until it reaches the navbar.
If there is not enough space, a good compromise is to scroll the container as far left as possible.

Link to comment
Share on other sites

  • Solution

Hello Samuele,

 

before I explain one possible way for how to get the scrollTo running as you described, here are some sidenotes:

  • It's best not use scroll-behaviour: smooth when working with ScrollTrigger because it will cause a delay in the browser reporting the correct scrollposition to ScrollTrigger, which might cause problems for you further down the road.
     
  • If you want to set specific dimensions on elements in a flex container, don't forget to set their flex-properties to allow the elements having that specific width, or flexbox will shrink/grow them as it thinks it's best to do ( I did in the example below by using the flex shorthand - https://css-tricks.com/snippets/css/a-guide-to-flexbox/#flex)

 

What you could do is instead of tweening each section indiviually for the fake-horizontal scroll, tween the container - this way you will be able to use the offsetLeft of each section for the calculations of the scrollTo (which will change once you have scrolled if you tween on each individual section, as it reports the offset to the parent element).

 

Substract the width of your navigation-sidebar from the offsetLeft and multiply everything by an offset, i.e. the discrepancy between the scroll-duration of the fake-horizontal ST and the amount of translating the container to the left - which I explained in this thread here (an example for scrollTo can be found at the very bottom of that linked post) and you should be good to go. Maybe that's a considerable alternative for you.

 

 

See the Pen wvrBbRq by akapowl (@akapowl) on CodePen

 

  • Like 6
Link to comment
Share on other sites

What should I say?
Thank you both, that's exactly what I was looking for! Nice explanation by the way.

  • Like 2
Link to comment
Share on other sites

Hi again, sorry for bother you but I still have a doubt.
Is it possibile to set a scroll animation for the elements inside the sections?

I'm trying this method but obviously the page doesn't scroll, any advice?
Thanks

 

  //text animation
  gsap.to(".second-slide-text", {
    scrollTrigger: {
      scroller: "",
      trigger: "#third-slide",
      start: "top 30%",
      end: "center 15%",
      scrub: true,
      toggleActions: "play pause reverse reverse",
      invalidateOnRefresh: true,
      markers: true,
    },
    y: -400,
    opacity: 1
  });

 

Link to comment
Share on other sites

I'm not sure I totally understand, but if you want to trigger animations when individual elements/sections come into view or pass a certain point in the viewport, best check out the containerAnimation property. This is from the ScrollTrigger docs:

 

containerAnimation Tween | Timeline - A popular effect is to create horizontally-moving sections that are tied to vertical scrolling but since that horizontal movement isn't a native scroll, a regular ScrollTrigger can't know when, for example, an element comes into view horizontally, so you must tell ScrollTrigger to monitor the container's [horizontal] animation to know when to trigger, like containerAnimation: yourTween. See a 

See the Pen 9be5d371346765a8c9a426e8f65f1cea by GreenSock (@GreenSock) on CodePen

 and more information here. Caveats: the container's animation must use a linear ease ( ease: "none"). Also, pinning and snapping aren't available on containerAnimation-based ScrollTriggers. You should avoid animating the trigger element horizontally or if you do, just offset the start/end values according to how far you're animating the trigger. 
  • Like 3
Link to comment
Share on other sites

  • 1 month later...

Hello @akapowl, I beg your pardon to return into this topic but I noticed something strange once resized the screen.
Actually this not happen in the codepen but in my website, so I cannot figured out where the bug is.

Basically when I click to an anchor link and then resizing the page the screen goes just a little bit further than the initial alignment.
I tried this method but nothing occured:


  function resize() {
    width = window.innerWidth;
    height = window.innerHeight;
  }

  ScrollTrigger.addEventListener("refreshInit", resize);
  resize();

1983753467_Schermata2022-01-17alle18_24_55.thumb.png.c0fe37c2730af52596d2228fdf2ba09e.png

Link to comment
Share on other sites

Right, @Samuele, it doesn't automatically re-position the scroll on each resize to where that anchor was in proportion to the current scroll position. You're changing the ratios when you resize. You'd need to add logic to handle that. I suppose you could record a variable that keeps track of which anchor the user navigated to, and then onRefresh() you could call your function again that animates there. Just one idea. Good luck!

Link to comment
Share on other sites

Hi there, thanks for the reply.
I do not feel is the right solution because this behavior happens everytime the window is resized.

It also happens without clicking any anchors, so in that case I could not have any variable that keeps track of which anchor the user navigated to...
Sorry but i feel a bit stuck. This is the current code:

      document.querySelectorAll(".anchor-item").forEach((element) => {
        element.addEventListener("click", function (e) {
          e.preventDefault();
          const id = this.getAttribute("href").split("#")[1];
          const targetElement = document.getElementById(id);
          const navBar = document.querySelector(".nav");

          const scrollToHere =
            (targetElement.offsetLeft - navBar.offsetWidth) *
            (scrollContainer.scrollWidth /
              (scrollContainer.scrollWidth - window.innerWidth));

          gsap.to(window, {
            scrollTo: scrollToHere,
            duration: 2,
          });
        });
      });

 

Link to comment
Share on other sites

10 hours ago, Samuele said:

this behavior happens everytime the window is resized.

That's exactly what I was saying. Yes, of course resizing the window fundamentally changes the ratios because your content is resizing but the browser's scroll position isn't moving to adjust for all those custom ratios in your content. That's not a bug in ScrollTrigger or anything - it's a fundamental issue with the logic in your demo. 

 

If you want it to maintain the ratios, you'd have to do that calculation and set the scroll position accordingly each time the window resizes. That's a very custom piece of logic and unfortunately we can't provide free custom consulting for everyone in these forums. If you still need help, feel free to post in the "Jobs & Freelance" forum to see if you can hire someone, or you can contact us if you'd like to explore paid consulting options from us. 

 

Good luck, @Samuele

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.
×