Jump to content
Search Community

SplitText Headers Flicker (Flash Briefly into View) on Page Transition

trackpad test
Moderator Tag

Go to solution Solved by elegantseagulls,

Recommended Posts

Sorry this project is too nascent to be published anywhere, so I am fishing for some more general guidance or advice, especially from anyone working in the contact of a React / Next.js implementation, as I suspect it is related to how things mount or are applied on the page transition of the parent, Layout.jsx.

 

I 100% understand this isn't ideal, the not sharing of code or offering an example you can inspect, and I will do that if I don't give up on the idea before I get a test site up. I also really don't expect a solution, but as I am soon pulling my last hair out I thought I would show you the issue, explain what I've tried, and see if you can suggest anything else based on your past experiences.

This is a screen recording that details the issue.

https://www.icloud.com/sharedalbum/#B1253qWtHytDIK;B919597C-1871-4978-9E3A-5B9497D7626C

 

The difficult part is it's not repeatable. Sometimes the ficker happens, sometimes it doesn't. I have tried a ton of different things in terms of restructuring the component, abstract different parts, applying delays, and CSS in JSX to set opacity to zero... I have also tried applying all the applicable will-change properties, and applied these to my h2
 

font-kerning: none;
-webkit-text-rendering: optimizeSpeed;
text-rendering: optimizeSpeed;
-webkit-transform: translateZ(0);
transform: translateZ(0);


So I am happy to answer more questions, and again, I know it's not ideal... I tried to migrate this to codesandbox but I had so many issues after spending 30 minutes with it I had to cut my losses and throw a Hail Mary here.

Key components are AnimatedHeader.jsx and useSplitText.js

 

import React, { useEffect } from "react";
import useSplitText from "../hooks/useSplitText";
import { gsap } from "gsap";
 
const AnimatedHeader = ({ headline }) => {
const [isSplitTextLoaded, SplitText] = useSplitText();
 
useEffect(() => {
if (isSplitTextLoaded) {
const childSplit = new SplitText("h2", {
type: "words",
wordsClass: "split-child",
});
const parentSplit = new SplitText("h2", {
type: "words",
wordsClass: "split-parent",
});
 
gsap.from(childSplit.words, {
duration: 1.25,
delay: 0.3,
autoAlpha: 0,
yPercent: 50,
ease: "back.out(1.2)",
stagger: 0.03,
});
}
}, [isSplitTextLoaded]);
 
return (
<>
<h2 className="will-change-transform split-parent block overflow-hidden pb-2 text-6xl text-stone-700">
{headline}
</h2>
<style jsx>{`
.split-parent,
split-child {
will-change: opacity, transform;
}
`}</style>
</>
);
};
 
export default AnimatedHeader;

 

 

import { useState, useEffect } from 'react';
import { gsap } from "gsap";
 
let SplitText;
 
const useSplitText = () => {
const [isLoaded, setIsLoaded] = useState(false);
 
useEffect(() => {
const loadSplitText = async () => {
SplitText = (await import('../src/scripts/SplitText.min.js')).default;
gsap.registerPlugin(SplitText);
setIsLoaded(true);
};
 
if (!SplitText) {
loadSplitText();
} else {
setIsLoaded(true);
}
}, []);
 
return [isLoaded, SplitText];
};
 
export default useSplitText;

 

<AnimatedHeader/> is then imported and placed on individual pages as needed.

 

 

Link to comment
Share on other sites

Thank you, @elegantseagulls ...setting visibility in tailwind seemed to present a problem with the cascade, or with autoAlpha anyway... setting it just kept the headers invisible. But I want to mark your suggestion as a solution because I think that is the answer in most other cases.

 

And after seeing the example you linked to and looking at others, it occurred to me that fromTo might be the correct approach? So I modified my code to use that...

 

gsap.fromTo(
childSplit.words,
// From properties
{
autoAlpha: 0,
yPercent: 100,
},
// To properties
{
duration: 0.6,
autoAlpha: 1,
yPercent: 0,
ease: "back.out(1.2)",
stagger: 0.04,
}
);

 

...and I *think* it's fixed :) Thanks for the nudge!

 

  • Like 1
Link to comment
Share on other sites

I posted maybe a bit prematurely. 😕 Funny story actually.. often I am guessing "issues" with GSAP get reported that are in fact attributable to a browser or OS being maxed out on memory or swap or compute resources.

 

Here it was sort of the opposite. Meaning, the perception I had that my issue had been fixed was probably a result of having a bunch of tabs open for a long time, and the browser dropping those errant frames in an effort to keep up. Restarting my browser actually exposed the problem had ...not been fixed.

 

So I am looking for a way to make use of autoAlpha and trying to understand the cascade of CSS in the context of this next.js app, and where/how to set the class in such a way that GSAP can unset it with autoAlpha.

 

Right now everything I am doing just results in the headline staying invisible. I've tried setting the style in a JSX <style> block just below the component and tried adding it to the stylesheet. Also tried applying via tailwind directly to the h2 element via invisible

 

Any other ideas? 🙏 

 

Link to comment
Share on other sites

This is my updated AnimatedHeader component, having applied what I learned about useLayoutEffect, gsap's context/cleanup, and how to properly format/paste code into this forum. 🙄😬


The problem remains unchanged, so I'm still looking for the best way to set visibility:hidden  in a way that gsap can access and undo.

 

import React, { useLayoutEffect } from "react";
import useSplitText from "../hooks/useSplitText";
import { gsap } from "gsap";

const AnimatedHeader = ({ headline }) => {
  const [isSplitTextLoaded, SplitText] = useSplitText();

  useLayoutEffect(() => {
    let ctx = gsap.context(() => {
      // all your GSAP animation code here

      if (isSplitTextLoaded) {
        const childSplit = new SplitText("h2", {
          type: "words",
          wordsClass: "split-child",
        });
        const parentSplit = new SplitText("h2", {
          type: "words",
          wordsClass: "split-parent",
        });

        gsap.fromTo(
          childSplit.words,
          // From properties
          {
            yPercent: 100,
            autoAlpha: 0,
          },
          // To properties
          {
            duration: 1,
            delay: 0.2,
            autoAlpha: 1,
            yPercent: 0,
            ease: "back.out(1.2)",
            stagger: 0.06,
          }
        );
      }
    });
    return () => ctx.revert(); // <- cleanup!
  }, [isSplitTextLoaded]);

  return (
    <>
      <h2 className="will-change-transform split-parent block overflow-hidden pb-2 text-4xl lg:text-6xl text-stone-700 font-playfair">
        {headline}
      </h2>
      <style jsx>{`
        .split-parent {
          will-change: opacity, transform;
        }
      `}</style>
    </>
  );
};

export default AnimatedHeader;

 

Link to comment
Share on other sites

Sorry to be erratic or overly confident in what look like solutions, but I always feel it's better to followup quickly so no one wastes time or energy trying to help with something that might be solved? :) 

 

TLDR; if you're using Next.js or react  – READ THIS, and try using useLayoutEffect even though React world would like you to use useEffect for most things for whatever reason... try both when you're having issues.

 

In the above example I forgot to work on the imported hook. Simply changing useEffect to useLayoutEffect in this file seems to have fixed the issue for me. No more momentary flicker, and headlines are gliding in.

 

So this is solving the FOUC issue for me in a way ...albeit without use of (or my successful application of ) visibility:hidden in CSS. It just works. I think. :) Restarted my browser a few times and can confirm the problem returns as I toggle back to useEffect on this imported hook.

 

Would still like to know why I can't get autoAlpha to dismiss my visibility:hidden property. But I'll save that for another thread when the issue comes up again and feels more urgent.

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