Jump to content
GreenSock

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

CSS properties incorrectly overwriting each other

Recommended Posts

TweenMax.set(obj,{backgroundImage:'url(path/to/img)', background:'black'})

This should result in the background being black with no image set. You're setting the background shorthand property second, which should overwrite any other background properties. jQuery does this correctly according to order. GSAP is merging them, setting a background image with a background color.

 

Yes, this should be considered a common use case. Taking one object with script defaults and merging them with another object containing user settings can result in this type of scenario.

 

I haven't done any testing, so I'm not sure what other CSS properties this behavior may be affecting.

Link to post
Share on other sites

On a side note:

New versions of jQuery set any needed vendor prefixes for the CSS properties you set. Greensock asserts that GSAP does this exceedingly well. So I was wondering if there are any benefits to using GSAP for this over jQuery, assuming both are already present, and we're only concerned with making simple CSS changes? Or do both do this pretty equally well?

Link to post
Share on other sites

Hi Gabriel,

 

What I can say is that is an expected behaviour and not related with GSAP or JQuery (for my understanding).

 

The thing is that background is a shorthand property, while background-image/-color/-repeat/-position and so on are the specific properties of the given element.

 

The good thing of a shorthand property is that it allows the developer to use just one line of code to set all of them, so instead of doing this:

#element{
    background-image:url('yourUrl.com');
    background-position: top left;
    background-repeat:no-repeat;
}

You can do this:

#element{
    background: url('yourUrl.com') top left no-repeat;
}

With the latter you're setting the same specific properties, ie, image, position and repeat but with less work.

 

A completely different property is background-color. So if you set the background-image, the background-color property is empty, therefore you can set it later. Then you're element will be black and if later you set the background-image again you'll see the image instead of the color. Basically is like doing this:

#element{
    backgound-image: url('yourUrl.com');
}
#element{
    backgound-color:#000;
}

Over and over...

 

As far as other properties facing the same issue font and border come to my mind right now, but basically every one that has a shorthand property to set the element's style.

 

To read more about it check the following links:

 

Official W3C page about the CSS2.1 specification:

http://www.w3.org/TR/CSS21/about.html#shorthand

 

Mozilla Developer Network:

https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties

 

Hope this helps,

Cheers,

Rodrigo.

Link to post
Share on other sites

I'm going to correct myself here.

 

When you use the shorthand property with a set() instance, it clears any previous data, so if you do as follow:

TweenMax.set(element, {background:'url("imgUrl.com")', background:'#000'});

If you check the element style with dev tools it'll have only the background-color property while the background-image will be empty.

 

If you use the complete properties like this:

TweenMax.set(element, {backgroundImage:'url("imgUrl.com")', backgroundColor:'#000'});

The element style will have both if you check the style with dev tools, both properties will have the given values in the TweenMax instance.

 

Cheers,

Rodrigo.

Link to post
Share on other sites

rhernando,
 
You didn't understand the problem I'm pointing out
 

I'm going to correct myself here.
 
When you use the shorthand property with a set() instance, it clears any previous data, so if you do as follow:

TweenMax.set(element, {background:'url("imgUrl.com")', background:'#000'});
If you check the element style with dev tools it'll have only the background-color property while the background-image will be empty.

 

 
This would be expected behavior, because the "background" shorthand property sets ALL of the explicit background properties at once (background-image, background-color, etc.). So if the browser had set any of those computed styles on a previous call, they would get overwritten by the shorthand property, while removing any undefined styles. Pretty much just like you pointed out already.
 
Thus:

TweenMax.set(element, {backgroundImage:'url("imgUrl.com")', background:'#000'});

This should remove the backgroundImage property since it wasn't defined in the successive shorthand declaration. Instead, it's combining both styles into one, which shouldn't happen.

I'm telling you, it's not behaving as it should. jQuery does this correctly, GSAP does not.

Link to post
Share on other sites

It is possible to add code to CSSPlugin to do the extra parsing for that type of scenario, but I must admit I'm ambivalent about doing that because:

  1. That type of usage (setting both a shorthand/group style like "background" as well as a more specific one, "backgroundImage" in the same call) should be discouraged anyway because not only does it not really make sense (in my opinion), but in the official specs for JavaScript, looping order on objects is not specified, meaning you cannot depend on the latter one in your object being set last in a for...in loop. Most browsers (if not all) happen to do it in a similar order right now, but there's no guarantee that'll continue in the future. 
  2. I'm very protective of file size. This seems like an edge case that could be easily remedied by coding your tween/set slightly differently, so I'm not sure it's worth the kb. Do you feel differently? 

As far as your original question about setting css via jQuery or TweenLite.set(), I'm honestly not sure which one is technically faster, but either one should be fine. Probably not a big difference except that GSAP can do more stuff like colors (including hsl, rgb, and almost any format you can think of) as well as 3D transforms that are individualized. In fact, for transforms, I'd definitely recommend using GSAP so that the values are segregated properly in case you want to tween them later (DEFINITELY animate with GSAP, not jQuery - it's much faster). 

 

Does that help?

Link to post
Share on other sites

That's fair enough. I wanted to point it out because "logically" a shorthand property should overwrite previous conflicting properties by order, like jQuery does. I'm not a fan of bigger file sizes either, so if you think this would be a big hit to file size, then maybe it's better left alone.

 

Although, in my mind, I do see this as a practical scenario for script authors. It's common practice for many scenarios to have a default configuration object, while allowing users to pass an object with overrides. Combining the objects can cause these conflicts, which an author may not catch until he starts getting bug reports. One could pass the default configuration to the dom first and then the user object, but that could cause flashing. So that leaves extra parsing to be done.

 

This doesn't affect me, since I already have jQuery loaded, and can use that. For others, the CSSPlugin has much of jQuery's goodness baked in, and might experience this more often using it exclusively as a CSS setter (to benefit from vendor prefixing).

 

So, that's my take. If file size will suffer, then I'd say leave it

Link to post
Share on other sites

Sure, I can definitely see how it would be annoying to encounter this if you weren't expecting it to happen this way. Unfortunately with the way styles cascade, ordering is important, and it is difficult to infer that order from a javascript object in a way that is, and always will be, consistent. I agree with Jack that it's hard to make sense of both background and backgroundImage in one tween.
 
I would suggest that "logically" a shorthand property actually has no precedence over the specific property, and vice versa, without the ordering of a style definition to provide the cascade. e.g.

background-image: url(img);
background: black;

is not equal to 

background: black;
background-image: url(img);

but it seems you are implying that the second option is the only one that makes sense when these two styles are found in a set of tween vars.
 
I don't think this is a case of jQuery is 'right' and GSAP is 'wrong', it's just that in this instance jQuery is applying these styles in the order that suits you. Anyway, if your default style is only 'background: black', wouldn't it make sense to just set the default as 'background-color: black' and eliminate this type of confusion?

  • Like 1
Link to post
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.

×