jeffdfarr Posted June 1, 2020 Posted June 1, 2020 I'm using Split Text but I get weird line breaks when animating. I believe it's due to not letting my custom font load first but I'm unsure how to solve this. I've gone through the forums but I haven't seen a clear answer. Here is the code I have... // Hero animation var heroTimeline = gsap.timeline({ paused:true, onComplete: () => {splitLines.revert()} }); const splitLines = new SplitText('.hero .block-animate', {type: "lines", linesClass: "line"}); $('.hero .block-animate .line').wrap('<div class="line-wrapper">'); heroTimeline.from(splitLines.lines, 1.25, {y: '150%', ease: "Power3.Out", stagger: 0.15}, 0.25); window.onload = () => { heroTimeline.play(); } See the Pen BajBJEV by jeffdfarr (@jeffdfarr) on CodePen.
jeffdfarr Posted June 1, 2020 Author Posted June 1, 2020 I can provide the live URL where I'm seeing this behavior but I don't know where to mark the message private.
ZachSaucier Posted June 1, 2020 Posted June 1, 2020 Hey Jeff. You should be able to have SplitText wait until your fonts are loaded by using document.fonts.ready.then(function () { // Your code here }); Keep in mind that the above won't work in IE due to browser support. 4
jeffdfarr Posted June 1, 2020 Author Posted June 1, 2020 That seemed to help on the drastic breaks but there are still some small line breaks issues. Here is my code below. Again, I can provide the live URL if hidden. // Hero animation document.fonts.ready.then(function () { var heroTimeline = gsap.timeline({ onComplete: () => {splitLines.revert()} }); const splitLines = new SplitText('.block-animate', {type: "lines", linesClass: "line"}); $('.block-animate .line').wrap('<div class="line-wrapper">'); heroTimeline.from(splitLines.lines, 1.25, {y: '150%', ease: "Power3.Out", stagger: 0.15}, 0.25); });
ZachSaucier Posted June 1, 2020 Posted June 1, 2020 19 minutes ago, jeffdfarr said: I can provide the live URL if hidden. Can you not re-create something similar in CodePen? It doesn't have to be the content that you're using on your actual site. Side notes: In GSAP 3, we recommend putting the duration inside of the vars parameter. Your ease is invalid: you should use either use the condensed string form ("power3") or the old object form (Power3.easeOut). You might want to use yPercent: 150 instead of y: '150%'.
jeffdfarr Posted June 1, 2020 Author Posted June 1, 2020 Okay, I updated the width to what it's like on the live site. ( See the Pen BajBJEV by jeffdfarr (@jeffdfarr) on CodePen. ) You can now see the weird breaking. Also, I will fix those side note issues. Thank you!
PointC Posted June 1, 2020 Posted June 1, 2020 Are you talking about that jump of the 'a' when you revert()? If so, I think adding a few pixels to your .container could fix things. See the Pen 37c21f64568617b2a425239944e57417 by PointC (@PointC) on CodePen.
jeffdfarr Posted June 1, 2020 Author Posted June 1, 2020 That seems like a bandaid to fix the problem. It does similar behavior for other sections of my website as well.
PointC Posted June 1, 2020 Posted June 1, 2020 Okay, how about setting font-kerning to none? See the Pen 5a400067e05977200814d5d09623287f by PointC (@PointC) on CodePen. 2
GreenSock Posted June 2, 2020 Posted June 2, 2020 Yep, it literally can't take kerning into account. It's impossible, not a bug. That's why this note has always been in the SplitText docs : Quote Some browsers (like Safari) apply custom kerning by default between letters, so when characters are split apart and put into their own divs, the spacing is slightly different. A bug has been filed with the Safari team (it’s a browser issue, not SplitText) but you can typically eliminate the differences by setting these CSS properties: font-kerning: none; -webkit-text-rendering: optimizeSpeed; text-rendering: optimizeSpeed; -webkit-transform: translateZ(0); transform: translateZ(0); Sorry, I wish I had better news for you. I can't think of any way to accommodate custom kerning like that. If anyone else has ideas, I'm all ears. 3
jeffdfarr Posted June 2, 2020 Author Posted June 2, 2020 Oh I didn't realize there was kerning on the font. That seemed to fix the problem. Thank you! 1
limbo Posted March 25, 2021 Posted March 25, 2021 Just to add - as this tiny fractional jump was being stubborn after .revert Some custom webfonts (the one I was using, of course) will force what looks like ligature adjustments (fi or ff for example) in Firefox and Safari (OSX Big Sur), regardless if these are set or unset with the CSS: font-kerning: none; -webkit-text-rendering: optimizeSpeed; text-rendering: optimizeSpeed; -webkit-transform: translateZ(0); transform: translateZ(0); -webkit-font-feature-settings:normal; font-feature-settings:normal; The only workaround I could find was to set css letter-spacing to a tiny increment like 0.01em. Ta, Liam 1
iDad5 Posted March 25, 2021 Posted March 25, 2021 I am prepared to get a lot of bashing for that comment, but I jus can not resist: There are times, when I really miss Flash. *duck* 1 1
limbo Posted March 30, 2021 Posted March 30, 2021 Last addition to this. On longer text passages... with some webfonts... with text over multiple lines... in safari (v/OS as above)... depending on line length and ragged edge paragraphs... sometimes words will find a home on the next line when .revert() has finished. Very ugly. The only way I could get round this was target safari and add <br> via the CMS where I needed them in the passage and be super mindful via media queries (I'm already detecting Safari as it is). Will also need to the run the splittext + revert again on resize. This won't work well for dynamic passages — where I'd imagine youd need to do something more fancy with line count. TLDR; Safari + SplitText + (some?) Custom webfonts are not kindred spirits
GreenSock Posted March 30, 2021 Posted March 30, 2021 @limbo thanks for sharing that. Yeah, as far as I can tell, that's purely due to the fact that Safari applies custom kerning only in certain scenarios, so if you split the text apart, it refuses to do that. If you have any specific suggestions for workarounds, I'm all ears. I'm curious: did you try setting tag: "span"?
limbo Posted April 7, 2021 Posted April 7, 2021 Hello Jack I did try tag:"span", — but as I'm using lines it doesn't seem help or make any difference in that respect. Thanks for the suggestion though.
limbo Posted April 22, 2021 Posted April 22, 2021 Still working on this and found a nice way to cope with the problems I was having with custom font... only run revert on resize. Seems obvious now. function debounce(func){ // to throttle var timer; return function(event){ if(timer) clearTimeout(timer); timer = setTimeout(func,150,event); // 150ms seems like a good sweetspot }; } window.addEventListener("resize",debounce(function(e){ mySplitText.revert(); })); Needs testing on device - works well on desktop inc. Safari OSX. 2
limbo Posted September 7, 2025 Posted September 7, 2025 On 6/1/2020 at 9:08 PM, ZachSaucier said: Hey Jeff. You should be able to have SplitText wait until your fonts are loaded by using document.fonts.ready.then(function () { // Your code here }); Keep in mind that the above won't work in IE due to browser support. This is so handy! Thanks.
Rodrigo Posted September 7, 2025 Posted September 7, 2025 Hi @limbo, With the complete re-write in version 3.13.0, SpliText also has the autoSplit config option and the onSplit callback: https://gsap.com/docs/v3/Plugins/SplitText/#autoSplit* https://gsap.com/docs/v3/Plugins/SplitText/#onSplit* For simple one-off animations that is super simple and the onSplit callback will be executed after the custom fonts are loaded, so it might be useful to have a peek at it. Happy Tweening! 1
NickWoodward Posted September 10, 2025 Posted September 10, 2025 dayuuum 😄 on topic: I've always wanted to use onSplit, but have been unsure how to have that work with splittext animations that are part of a larger timeline that can't really be defined in that callback? 1
Rodrigo Posted September 10, 2025 Posted September 10, 2025 Hi Nick! In the case of using a Timeline that is created outside the onSplit callback, you have to add a label to position the text animation and shift the next Tween the amount of seconds the text animation lasts in order to properly create the sequence. The main issue here is the fact that the custom font could be loaded after the rest of the Timeline is created, so the the challenge is to kind of squeeze (for lack of a better word) or properly fit the SplitText animation in the Timeline without causing a problem for the rest of the sequence. This is an extremely simple demo that show this approach: See the Pen MYadwOP by GreenSock (@GreenSock) on CodePen. Is worth mentioning that you can also use shiftChildren if you can't anticipate the duration of the SplitText animation: https://gsap.com/docs/v3/GSAP/Timeline/shiftChildren() Hopefully this helps Happy Tweening! 1
GreenSock Posted September 10, 2025 Posted September 10, 2025 Actually, here's a fork that demonstrates a way that might be easier: See the Pen MYadarw?editors=0010 by GreenSock (@GreenSock) on CodePen. The helper function that's key: /* This helper function can be used just like a regular SplitText except that it returns the animation from the onSplit() so that you can insert it into a timeline (or do whatever you want with it). It also handles killing that animation when onSplit() is called again, and it'll swap the new animation into exactly where the old one was, making it seamless. For example: let tl = gsap.timeline(); tl.to(...) .add( SplitTextAnimation(target, { type: "words,chars", onSplit(self) { return gsap.from(self.chars, {y: 100, stagger: 0.1}) } }) ) .to(...); */ function SplitTextAnimation(target, config) { let animation, onSplit = config.onSplit; config.onSplit = self => { let parent, startTime; if (animation) { parent = animation.parent; startTime = animation.startTime(); animation.kill(); } animation = onSplit && onSplit(self); parent && parent.add(animation, startTime || 0); } SplitText.create(target, config); return animation; } That way, you don't have to pre-calculate the duration/stagger and offset subsequent animations using the position parameter. Remember, the onSplit() will get called immediately, and then again when the fonts load. Don't forget to return the animation in the onSplit() because that's what allows it to get funneled back to the helper function which passes it along too. I hope that helps!
NickWoodward Posted September 10, 2025 Posted September 10, 2025 7 minutes ago, GreenSock said: Actually, here's a fork that demonstrates a way that might be easier: The helper function that's key: /* This helper function can be used just like a regular SplitText except that it returns the animation from the onSplit() so that you can insert it into a timeline (or do whatever you want with it). It also handles killing that animation when onSplit() is called again, and it'll swap the new animation into exactly where the old one was, making it seamless. For example: let tl = gsap.timeline(); tl.to(...) .add( SplitTextAnimation(target, { type: "words,chars", onSplit(self) { return gsap.from(self.chars, {y: 100, stagger: 0.1}) } }) ) .to(...); */ function SplitTextAnimation(target, config) { let animation, onSplit = config.onSplit; config.onSplit = self => { let parent, startTime; if (animation) { parent = animation.parent; startTime = animation.startTime(); animation.kill(); } animation = onSplit && onSplit(self); parent && parent.add(animation, startTime || 0); } SplitText.create(target, config); return animation; } That way, you don't have to pre-calculate the duration/stagger and offset subsequent animations using the position parameter. Remember, the onSplit() will get called immediately, and then again when the fonts load. Don't forget to return the animation in the onSplit() because that's what allows it to get funneled back to the helper function which passes it along too. I hope that helps! Amazing, thanks. Just always something I've wondered, and I've been ignoring console warnings about splittext so far because I haven't quite known how to deal with it 😊 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now