Jump to content
GreenSock

GSAP 3.10 Released


| GreenSock
34326

 

Introducing ScrollSmoother.🥳

A shiny new plugin, exclusively for Club GreenSock members!

ScrollSmoother makes it simple to add a buttery smooth vertical scrolling effect to your ScrollTrigger pages. Under the hood, ScrollSmoother leverages native scrolling which allows it to sidestep many of the accessibility annoyances that plague smooth-scrolling sites. No fake scrollbars, and no messing with pointer or touch functionality. 


 

ScrollSmoother.create({
  content: "#smooth-content",
  wrapper: "#smooth-wrapper",
  smooth: 1, // how long (in seconds) it takes to "catch up" to the native scroll position
  effects: true, // looks for data-speed and data-lag attributes on elements
  normalizeScroll: true, // prevents address bar from showing/hiding on most devices, solves various other browser inconsistencies
  ignoreMobileResize: true // skips ScrollTrigger.refresh() on mobile resizes from address bar showing/hiding
});

Effects... 

ScrollSmoother will integrate seamlessly with all your scroll-triggered animations. but we've also added some bonus ScrollSmoother effects. 

  • speed - Great for parallax effects! It adjusts the speed at which an element moves vertically while scrolling through the viewport. A speed of 1 is normal speed, 2 is double speed, etc.
  • lag - Add some lag* to gently flow elements behind the scroll before they ease back to their natural scroll position. 

* no seriously, trust us. It's the good kind of lag.

<div data-speed="0.5"></div> <!-- half-speed of scroll -->
<div data-speed="2"></div> <!-- double-speed of scroll -->
<div data-speed="1"></div> <!-- normal speed of scroll -->

<div data-lag="0.5"></div> <!-- takes 0.5 seconds to "catch up" -->
<div data-lag="0.8"></div> <!-- takes 0.8 seconds to "catch up" -->

Read the docs for all the juicy details, or pull up a seat and watch this short explainer video.

Observer

The brand new 3.5kb Observer plugin offers a super-flexible, unified way to sense meaningful events across all (touch/mouse/pointer) devices without wrestling with all the implementation details. Perhaps you want to respond to "scroll-like" user behavior which could be a mouse wheel spin, finger swipe on a touch device, a scrollbar drag, or a pointer press & drag...and of course you need directional data and velocity. No problem! Tell Observer which event types to watch (wheel, touch, pointer, and/or scroll) and it will collect delta values over the course of each requestAnimationFrame tick (debounced for performance by default) and automatically determine the biggest delta and then trigger the appropriate callback(s) like onUp, onDown, onDrag, etc. 

Look how easy it is to trigger next()/previous() functions based on when the user swipes up/down or uses their mouse wheel:

Observer.create({
  target: window,         // can be any element (selector text is fine)
  type: "wheel,touch",    // comma-delimited list of what to listen for ("wheel,touch,scroll,pointer")
  onUp: () => previous(), 
  onDown: () => next(),
});

Demo

Notice there's no actual scrolling in the demo below but you can use your mouse wheel (or swipe on touch devices) to initiate movement so it "feels" like a scroll:

Since ScrollTrigger leverages Observer internally for normalizeScroll(), we exposed it via ScrollTrigger.observe() so you don't have to load an extra file if you're already using ScrollTrigger. 

Excited? Why don't you observe this video or check out the docs (see what we did there?).

gsap.quickTo()

If you find yourself calling gsap.to() many times on the same numeric property of the same target, like in a "mousemove" event, you can boost performance by creating a quickTo() function instead. Think of a quickTo() like an optimized function tied to one particular numeric property, where it directly pipes a new number to it.

Example

let xTo = gsap.quickTo("#id", "x", {duration: 0.4, ease: "power3"}),
    yTo = gsap.quickTo("#id", "y", {duration: 0.4, ease: "power3"});

document.querySelector("#container").addEventListener("mousemove", e => {
  xTo(e.pageX);
  yTo(e.pageY);
});

Mouse Follower Demo

 

ScrollTrigger.normalizeScroll() and ignoreMobileResize

Have you ever run into these problems?:

  • Address bar on mobile browsers shows/hides and resizes the viewport, causing jumps
  • When scrolling fast, a pinned element seems to shoot past for a brief moment and then jump to the correct pinned position (multi-thread synchronization issues)
  • iOS jitter
  • Overscroll behavior that seems impossible to prevent on iOS
  • Inconsistent momentum scrolling across devices

The powerful new normalizeScroll() functionality intercepts native browser scroll behavior and handles it on the JavaScript thread instead which solves the problems mentioned above on most devices (iOS Phones in portrait orientation still show/hide the address bar). To enable it, simply:

ScrollTrigger.normalizeScroll(true);

To prevent ScrollTrigger.refresh() from running (and recalculating start/end positions) when a mobile browser shows/hides its address bar, you can now do:

ScrollTrigger.config({ ignoreMobileResize: true });

So easy!

Read more in the docs.

New "*=" and "/=" relative prefixes

You've always been able to add or subtract from the current value, like:

gsap.to(".box", {
  x: "+=100", // 100 more than the current value
  y: "-=100", // 100 less than the current value
});

...and now you can multiply or divide accordingly:

gsap.to(".box", {
  x: "*=2", // double the current value
  y: "/=2", // halve the current value
});

 

And more...

GSAP 3.10 also delivers various bug fixes, so we'd highly recommend installing the latest version today. There are many ways to get GSAP - see the Installation page for all the options (download, NPM, zip, Github, etc.).

Resources

Happy tweening!

  • Like 8
  • Thanks 1
  • Haha 1

Get an all-access pass to premium plugins, offers, and more!

Join the Club

Have you exercised your animation superpowers today? Go make us proud and tell us about it.

- Team GreenSock



User Feedback

Recommended Comments

3 minutes ago, omarel said:

Will this be available to be used with React?

Absolutely, GSAP is just vanilla JS with no dependencies, so you can use it in any framework including React. Check out this article about using GSAP in React:

 

Have fun!

Link to comment
Share on other sites

5 hours ago, omarel said:

So excited about this. 
 

Will this be available to be used with React?

 

Check out this question of mine where 2 methods of adding to React are provided. The solution from @OSUblake using contexts is the better one because it will allow children of page components to access the ScrollSmoother instance.

 

 

Link to comment
Share on other sites

10 hours ago, JoeH said:

Just noticed that it works with iframes too, what kind of wizardry did that involve?

 

**Magic** ;)

 

Nah, that's probably just because ScrollSmoother leverages native scrolling by default, so it's not faking scrollbars or intercepting touch/pointer/mouse/wheel events, etc. 

Link to comment
Share on other sites

4 hours ago, Sign Up said:

position:fixed will handle when using ScrollSmoother?

You can put position: fixed elements outside the wrapper. Or you can use ScrollTrigger's pinning feature of course.

Link to comment
Share on other sites

@GreenSock I feel very bad using these 2 ways. way 1 you have to append the div outside the tag. and method 2 is not much better when using the battery of gsap.  If the user wants the style fixed for mobile, and disable in desktop. So we have to use more matchMedia.

Why don't we create an option so the user can enable or disable it and customize the fixed. Currently fixed is used a lot in my project, if I do the above 2 ways, it will break a lot.

Link to comment
Share on other sites

Smooth scrolling is changing quite central behaviour, positioning will act differently because of the wrapper. So it does come with some compromises.

You can kill() and reinstate the smooth scroll if necessary, that's another option. Maybe that's what you're after? Thread attached.

IMO it would be easiest to move the modals outside the wrapper though - you could even use JS to reparent if you want to keep them in the correct place in the DOM by default.
 

  • Like 1
Link to comment
Share on other sites

Thanks for the code examples! I just figured there is a small mistake in the following example. It's missing a comma after "normalizeScroll: true".

 

ScrollSmoother.create({
  content: "#smooth-content",
  wrapper: "#smooth-wrapper",
  smooth: 1, // how long (in seconds) it takes to "catch up" to the native scroll position
  effects: true, // looks for data-speed and data-lag attributes on elements
  normalizeScroll: true // prevents address bar from showing/hiding on most devices, solves various other browser inconsistencies
  ignoreMobileResize: true // skips ScrollTrigger.refresh() on mobile resizes from address bar showing/hiding
});
  • Like 1
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

×