Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
bluemilker

Is it possible to tween CSS Pseudo-Elements (like :after)?

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

I've been playing around with GSAP, and I'm really enjoying the experience so far.

 

I was wondering if there was any way to address the CSS applied to pseudo-elements like :before and :after, using GSAP. I've been looking around, and it seems like these elements aren't even really in the DOM, by default, and are tricky to address. Is it possible to somehow change the CSS without addressing the element itself?

 

Thanks in advance.

Link to comment
Share on other sites

That is indeed tricky because those aren't DOM elements so there's no way to reference them in JavaScript. However, I think I have a solution. It is possible to get the actual style sheet data and tween THOSE values (which would affect objects with that style globally on the page rather than a single element). For example, if you have a CSS class named ".myClass" that sets a background-color to "#FF0000", you could tween that to a different color and ALL of the objects on the page that use ".myClass" would have their background color change. See what I mean?

 

I whipped together a CSSRulePlugin that should help with this. Here's how it works...

 

The plugin itself actually has a static "getRule()" method that you can use to grab a reference to the style sheet itself based on the selector you used in your CSS. For example, let's say you have CSS like this:

 

.myClass {
color:#FF0000;
}
.myClass:before {
content:"This content is before.";
color:#00FF00;
}

 

Now let's say you want to tween the color of the .myClass:before to blue. Make sure you load the attached CSSRulePlugin.js and then you can do this:

 

var rule = CSSRulePlugin.getRule(".myClass:before");
TweenLite.to(rule, 3, {cssRule:{color:"#0000FF"}});

 

And if you want to get ALL of the :before pseudo elements, the getRule() will return an array of them, so I could do this:

 

TweenLite.to( CSSRulePlugin.getRule(":before"), 3, {cssRule:{color:"#0000CC"}});

 

I haven't done extensive testing on CSSRulePlugin, but it seemed to work in all the major browsers. I'd love to hear what you think. Just keep in mind that it is typically best to tween a value that has already been defined in the rule that you're selecting because it cannot do a calculated style. For example, if we didn't define any color initially for the .myClass:before and tried to tween its color to blue, it would start transparent and go to blue. One way around this is to simply set your starting values explicitly in the tween by doing a fromTo(). That way there's no having to guess what the starting value is supposed to be when it isn't defined previously.

 

In summary, the CSSRulePlugin allows you to tween the style sheet rule itself rather than a particular DOM element's style property. Don't forget to wrap your values in a cssRule:{} object.

 

Does this help?

CSSRulePlugin.zip

  • Like 3
Link to comment
Share on other sites

Thanks, Jack! I wasn't expecting this level of help, and I really appreciate it.

 

I've gotten your plugin working on a test page, but I'm running into one issue:

 

I can apply tweens to all pseudoelements on the page using the getRule(":before") syntax. But for some reason, getRule is failing when I try to find a specific instance of one, such as getRule(".myClass:before").

 

I've put together a quick test page to show what I mean.

 

https://dl.dropbox.com/u/56154/gstest/pseudoelement_tweens.html

 

There are three tweens being called on the page. The red box tweens to yellow, all :before elements have a yoyo-ing tween of their border width, and theoretically the text in the :after element should be tweening to white. But the last one isn't working, and the javascript console reports that getRule is returning undefined.

 

Am I making an obvious error?

Link to comment
Share on other sites

Aha, it looks like IE adds an extra ":" to the selector when you're using a pseudo element, so .myClass:after becomes .myClass::after. Gotta love Microsoft. Anyway, here's a revised file that should work around that difference. Does this work better for you?

CSSRulePlugin.zip

  • Like 1
Link to comment
Share on other sites

That fixed it! Thanks so much for your help. I'm blown away. :)

Link to comment
Share on other sites

  • 1 year later...

Hi Jack,

 

I'm working with this plugin to animate some :before and :after borders, and am having trouble getting the plugin to work on a specific element that had a class applied dynamically with jQuery.

 

My situation is this: I have a gallery of photos. Clicking on a photo should animate just that photo's container (which has the :before and :after pseudo elements). I'm able to animate all photo containers at once, but not just the container clicked.

 

I get the error Uncaught TypeError: Cannot call method 'split' of undefined. Here is my code:

 
$( '.hexagon' ).click( function() {
    var hexAnimation = new TimelineLite();
    var hexagon = $( this );

    hexagon.addClass('onhex');

    var hexBeforeCSS = CSSRulePlugin.getRule( '.onhex:before' );
    var hexAfterCSS  = CSSRulePlugin.getRule( '.onhex:after' );

    TweenLite.to( hexBeforeCSS, 3, { cssRule: { ... } } );
    TweenLite.to( hexAfterCSS, 3, { cssRule: { ... } } );

    hexAnimation.add(
        TweenMax.to( $( this ), 3, { ...tween... } )
    );
} )

I also tried adding the .onhex pseudo elements to my CSS file, but doing so makes the borders snap to the end dimensions immediately, skipping the animation.

 

Here is an example of what's happening:

 

http://staging.factionmedia.com/fmwebsite/about/

 

 

Bottom line: I don't know how to target just one element and wonder if you can help.

 

Thanks!

Link to comment
Share on other sites

Hmm I'm not 100% sure I'm grasping the effect you're trying to achieve here, and I can't make your site throw any errors related to GreenSock. Perhaps you could try making a reduced test case at codepen or jsfiddle so we can get to the bottom of it?

 

Just so you are aware, tweening rules with the CSSRulePlugin is just like making live changes to your CSS file - it is not the same as an inline style that is specific to that element. Any change to a CSSRule will apply to any element that would normally receive styles from that rule. If you want to tween pseudo elements individually, you'll need to have individual rules for each element.

 

See if this helps at all:

See the Pen ibHAt by jamiejefferson (@jamiejefferson) on CodePen

  • Like 2
Link to comment
Share on other sites

  • 5 years later...

Greetings,

 

Is this possible to use in conjunction with TimelineMax? For example:

 

Quote

var rule = CSSRulePlugin.getRule(".site-footer:before");
var tl = new TimelineMax({repeat:-1});
tl.to(rule, 3.5, {cssRule:{backgroundPosition:"-35px 100%"}});

 

Link to comment
Share on other sites

Yes, a CSSRule tween can be part of a timeline.

 

Happy tweening.

:)

 

  • Like 4
Link to comment
Share on other sites

Hello @webrhythm and Welcome to the GreenSock Forum!

 

Here is an example of using the CSSRulePlugin with a GSAP timeline, using TimelineMax.

 

See the Pen eMLogz by jonathan (@jonathan) on CodePen

 

Happy Tweening! :)

  • 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.
×