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!