Jump to content
Search Community

ScrollTrigger, MatchMedia, NextJS (Works and stops on resize)

ridge test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

I'm struggling a bit with matchMedia + ScrollTrigger.

 

I've been battling this for about 6 hours now and have commented out parts of the website piece by piece to narrow down the issue(s).

 

For some reason - (if it's above the min-width I've set) the scrolltrigger / animation works as intended.

 

When I resize the browser below the matchmedia width, scroll trigger shuts off correctly, but when I resize it back, scrolltrigger ceases to work. It just ends up stuck in place and the "onUpdate" callback never gets fired.

 

I've commented out chunks of html unrelated to the component using scrolltrigger, I've also commented out the mediaqueries that modify the component design (when the scrolltrigger should be disabled based on the media query).

 

It works with these parts commented out, but when I add them back in, it stops.

 

Without the matchmedia function, it continues to work while I shrink and expand the browser window.

 

----

 

I am still new to gsap, so I am wondering if there is anything obvious I am missing and/or should be looking for. Or -- if anyone has experienced this type of issue before.

 

I know you will want to see a simplified working demo, but there are so many parts I have found that cause it to "stop" working, I am not sure how to reduce it -- so, I figured i'd start with general feedback/recommendations.

 

Here is the scrolltrigger code with matchmedia:

 

/**
*
*   Content Block
*       - A left/right content block + image or video
*
**/
'use client';

import Config from '@/config';
import Image from '@/modules/image';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { useState, useLayoutEffect, useRef } from 'react';

//Load Module
gsap.registerPlugin(ScrollTrigger);

//Build the Element
export default function ContentBlock( props ){

    let creative    = '',
        content     = [],
        classes     = ['block','container'],
        ref         = useRef();

    //Set a Default Direction
    if( !props.direction )
        props.direction = 'left';

    //Allow it to be changed
    if( props.direction && ['left','right'].indexOf( props.direction ) > -1 )
        classes.push( props.direction );

    //Image
    if( props.image )
        creative = (
            <div className="image creative">
                <Image { ...props.image } />
            </div>
        );

    //Video
    if( props.video )
        creative = (
            <div className="video creative">
                <iframe { ...props.video } />
            </div>
        );

    //Title
    if( props.content.title )
        content.push(
            <header key={ props.id + '-header' }>
                <h2 dangerouslySetInnerHTML={{
                    __html: props.content.title
                }} />
            </header>
        );

    //Body
    if( props.content.body )
        content.push(
            <div key={ props.id + '-body' } dangerouslySetInnerHTML={{
                __html: props.content.body
            }} />
        );

    //Buttons
    if( props.content.buttons )
        content.push(
            <div className="buttons" key={ props.id + '-buttons' }>
                { props.content.buttons }
            </div>
        );

    //On Mount
    useLayoutEffect(() => {

        //If this block doesn't have animation, just return
        if( !props.animate ) return;

        //Prepare
        let mm          = gsap.matchMedia(),
            animations  = [{
                selector:   '.creative',
                from:       { yPercent: 5 },
                to:         { yPercent: -5 },
            },{
                selector:   '.content',
                from:       { xPercent: 1 },
                to:         { xPercent: -1 },
            }];

        //
        mm.add('(min-width: 1100px)', context => {

            //The Container
            let $container  = ref.current;

            //Loop through
            animations.forEach( ({ selector , from , to }) => {

                //Prepare timeline
                let timeline = gsap.timeline({
                    scrollTrigger: {
                        trigger:                $container,
                        invalidateOnRefresh:    true,
                        markers:                true,
                        scrub:                  true,
                        start:                  'top center',
                        end:                    () => "+=" + $container.offsetHeight
                    }
                });

                //Initiate
                timeline.fromTo( selector , from , to );

            });


        }, ref);


        return () => mm.revert();

    },[]);


    //Return
    return (
        <section id={ props.id } key={ props.id } ref={ ref } className={ classes.join(' ') }>
            <div>
                { creative }
                <div className="content">
                    <div>
                        { content }
                    </div>
                </div>
            </div>
        </section>
    );

}

 

Appreciate anyone's help!

Link to comment
Share on other sites

  • Solution

Welcome to the forums, @ridge. There was a regression in 3.12.3 that could cause ScrollTriggered animations to stop working after resizing if they were created inside a matchMedia(), but that has been fixed in the latest release so please make sure you're using at least 3.12.4. Sorry about any confusion there. 

 

If you're still having trouble, please provide a minimal demo, like a Stackblitz that clearly shows the issue and we'd be happy to take a peek. Here's one you can fork: 

https://stackblitz.com/edit/react-cxv92j

 

And we'll be announcing this React hook soon, but you can use it now to simplify some of the React-related stuff: 

https://www.npmjs.com/package/@gsap/react

 

Hopefully that'll get you going in the right direction. Have fun!

  • Like 2
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...