Jump to content


How to get :after pseudo-element

Moderator Tag
Go to solution Solved by OSUblake,

Recommended Posts


How can I select :after and :before pseudo-element without the CSSRulesPlugin? This plugin have been deprecated not long ago. Can anyone provide me an example?


Link to comment
Share on other sites

  • Solution

Welcome to the forums @Imperyum


It's in the docs, but I would recommend using CSS variables instead. You can't target an element with that plugin, only rules.



Link to comment
Share on other sites

  • 11 months later...

Thanks for this solution @OSUblake, it was just what I needed to achieve my animation with pseudo-element.

Experiencing a slight a hang-up though: When I upgraded from GSAP 3.10.4 to 3.11.4, my pseudo-element no longer animates (using this technique).

Is it me, or is this no longer possible in GSAP 3.11.4?


RESOLVED: This IS still possible in GSAP 3.11.4

Edited by clayteller
This IS still possible in GSAP 3.11.4
Link to comment
Share on other sites

Hi @clayteller. I didn't quite understand what you meant - are you animating CSS variables the way Blake suggested or are you saying that you were using CSSRulePlugin to animate CSS rules and it doesn't work anymore in 3.11.4? Can you please provide a minimal demo, like in CodePen? 


Here's a starter CodePen that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen


If you're using something like React/Next/Vue/Nuxt or some other framework, you may find StackBlitz easier to use. We have a series of collections with different templates for you to get started on these different frameworks: React/Next/Vue/Nuxt.


Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. 

Link to comment
Share on other sites

@GSAP Helper and @GreenSock thanks so much for quick reply! Sorry for confusion, I'm animating CSS variables. I'll set up a codepen demo and follow up shortly.

Link to comment
Share on other sites

@GreenSock I forked your pen and modified it to use css variable. It does work in my pen.

See the Pen vYzXMwG by clayteller (@clayteller) on CodePen


Hmm well I'm stupefied now.


I swear it stopped working after I changed this line in my code:


to this


And then started working again after I changed it back.


Thanks for your help! I'll try to figure out what's going on. Now If feel guilty for hijacking this thread with false info. Feel free to delete these messages. 😊

Link to comment
Share on other sites

Yeah, the CSS variables demo seems to work fine in 3.11.4 too, right?

See the Pen PowWgOz by GreenSock (@GreenSock) on CodePen


2 minutes ago, clayteller said:

Thanks for your help! I'll try to figure out what's going on. Now If feel guilty for hijacking this thread with false info. Feel free to delete these messages. 😊

No worries! 


We definitely want to squash any bugs, so if you notice anything odd please do let us know ASAP. We're prepping the next release now. 

Link to comment
Share on other sites

Went back to my code and doublechecked and the animation in my project definitely works when GSAP 3.10.4 is loaded, but stops working after I update my CDN link and GSAP 3.11.4 is loaded. I confirmed this Chrome dev tools. I don't get it!


Clearly it's something on my end though if it works in codepen. Well, here's my code in case someone can spot something weird that I'm not seeing. Here's the site https://ng-conf.org/.


 * Animate the home title when page loads.
export const homeTitle = () => {
	const title = document.querySelector( '.home .title' );

	// Bail if there's no home title
	if ( ! title ) {

	const tl = gsap.timeline();

	// Wait for page to load before starting animation
	window.addEventListener( 'load', function() {
			// Title is hidden with CSS to prevent FOUC, so make it visible before animation starts
			.from( title, {
				autoAlpha: 0,
				duration: 0,
			} )
			// Animtate the title from invisible to full size
			.from( title, {
				duration: 0.8,
				ease: 'power4.in',
				scale: 0,
			} )
			// Animate the "10th Edition" subtitle, which is a pseudo-element and uses a css custom property "--beforeScale"
			.from( title, {
				'--beforeScale': 0.8,
				duration: 1.2,
				ease: 'elastic.out(1, 0.3)',
			} );
	} );

Definitely no obligation to help me further since this seems to be on me. Thanks for all your time on here helping people!

Link to comment
Share on other sites

I think I see what's happening...


You're using the new CSS property named "scale" which is sorta like a shortcut for applying a scale transform: 

/* universally compatible */
transform: scale(2);

/* new shorter way of doing the same thing (most browsers support) */
scale: 2;

However, these new "shortcuts" that browsers meant as a help actually can cause a lot of headaches because what's supposed to happen when you've got BOTH a transform AND some of the shortcuts applied? Uh oh. Should they be combined? If not, which should "win"? If GSAP applies the scale via the historically standard "transform" value but you've got your CSS set up with the shortcut...what do you expect should happen? 


What's even worse is that if you try to read the computed values from the browser (which GSAP typically must do to get the "current" values to interpolate), they aren't merged. So in your example if we ask the browser what the transform is, it'll report there is no transform...but you've got a scale applied! Of course we could read BOTH and try to merge all the data inside GSAP (more expensive), but how is GSAP supposed to know what you mean when you do something like this: 

gsap.to("#el", {scale: 3})

Do you mean scale or transform: scale (which functionally are identical!)? Where should GSAP apply it? 


One of GSAP's strengths is that how it handles transforms: 

  • Allows for independent control/animation of every component (x, y, z, scaleX, scaleY, rotation, rotationX, rotationY, skewX, skewY, etc.) which is a BIG deal for animators. You still cannot do that even with the new spec in CSS because you can't separate x and y for example. So you get a subset of the options in CSS whereas GSAP gives you full control of them all. 
  • Normalizes behavior across browsers (applies prefixes when necessary, solves browser quirks with SVGs, makes them work like normal elements with transformOrigin, etc.)
  • Delivers a consistent order of operation in transforms
  • Plus you get additional features, like rotations going in certain directions by adding suffixes like _short, _cw, and _ccw, plus svgOrigin and a lot more. 

The most reliable way of apply transforms is via the "transform" CSS property. Every browser supports it, plus you get unlimited control of all the components whereas if you try tapping into the scale, translate, and rotate new properties, you're limited. So in GSAP, we standardize on using "transform". However, what happens if someone sets up their CSS with the newer components? UGH! Well, GSAP does parse them but since we're applying them via the "transform" property (to harmonize support across all browser and deliver maximum flexibility), we MUST set the individual components to "none" to prevent cross-contamination. 


In GSAP 3.11, we implemented that (setting the individual components to "none" on anything that GSAP is animating transforms on). Again, it's to prevent contamination from your CSS. 


The moral of the story is: use GSAP for all your transforms whenever possible. If you need to set things up initially in your CSS, do that via the "transform" property, not the newer translate/scale/rotate properties which are more like band-aids for browsers trying to let CSS animations to more of what GSAP has been able to do for more than a decade. :)

Is there some reason you were using a CSS variable to animate the scale like that instead of just using GSAP directly?  


Solution summary: instead of using the "scale" CSS property, put that into the "transform" property like transform: scale(...). Better yet, use GSAP directly to set/animate that value. 


Does that clear things up? 

  • Like 1
Link to comment
Share on other sites

@GreenSock thanks so much for that great explanation! I think I just wasn't using my brain is why I used a CSS variable instead of animating directly with GSAP. ChatGPT won't be replacing this forum anytime soon. 😄 Thanks!

  • Like 1
Link to comment
Share on other sites

@GreenSock sorry, I spoke to soon about not using my brain: I'm using CSS variable instead of direct GSAP because I need to animate a pseudo-element.

So, I tried suggestion of using

transform: scale( var(--beforeScale) );

instead of 

scale: var(--beforeScale);

but it still not working for me using GSAP 3.11.4. The update is here if you have time to take a peek: https://ngstaging.ng-conf.org/


Should I use CSSRulePlugin instead to help me animate pseudo-element? Would I need to be Club member to use that plugin?

Link to comment
Share on other sites

Minimal demos are always more useful than live sites - I'm not quite certain what's going on but it's not a GSAP 3.11.4 thing.

Works for me over on codepen, can you reproduce the issue for me using your code on codepen?


See the Pen 57dec0742845f7c3e5f1c4d67e2add19 by cassie-codes (@cassie-codes) on CodePen

  • Like 1
Link to comment
Share on other sites

Thanks @Cassie I updated my previous codepen fork I posted with the code from my project.


When the animation works, the pseudo-element will kind of pop into full size after the title animates to full size. You can see in the pen the pseudo-element is not animating.


I appreciate your help.


See the Pen vYzXMwG by clayteller (@clayteller) on CodePen

  • Like 1
Link to comment
Share on other sites

Aha! Thanks for the minimal demo. I see exactly what the problem is now, and it wasn't your fault....


You named your variable with a capital letter in it. We did a bunch of work on the core in 3.11 to accommodate the brand new revert() feature (which undergirds gsap.matchMedia() and gsap.context()), and that necessitated implementing a way to roll things back which is leveraged in .from()/.fromTo() animations. For CSS-related values, those must be removed which requires dash syntax for property names in the element.style.removeProperty() method (whereas when you directly set the property value, it's camelCase, like element.style.backgroundColor = "blue" vs element.style.removeProperty("background-color")). GSAP was converting the camelCased name to the dash syntax in that case, so your --beforeScale became --before-scale, thus it wasn't actually getting removed properly. It should be resolved in the next release which you can preview at:



Or you can simply change your CSS variable to not be camelCased:

See the Pen QWVGpyK?editors=0010 by GreenSock (@GreenSock) on CodePen


Does that clear things up? Sorry about the confusion there. I hadn't anticipated someone using a camelCased CSS property name. 

  • Like 1
Link to comment
Share on other sites

@GreenSock awesome! I'll take the blame because I definitely don't normally use camelCase in CSS, I guess I must've been in the javascript frame of mind when I did that. Thanks so much for your help!

Link to comment
Share on other sites

Well I'm actually glad you did it because it helped expose something we should fix. So thanks for making that "mistake" :)


Glad it's all worked out now. Good luck with your launch. 

  • Like 2
  • Haha 1
Link to comment
Share on other sites

What a sneaky bug! So glad we found that and I hereby eat my words!



I'm not quite certain what's going on but it's not a GSAP 3.11.4 thing.


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.