Jump to content
GreenSock

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

Animating to/from backgroundSize: "contain" or "cover"

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 was asked yesterday about animating to/from backgroundSize: "cover" or "contain" with GSAP, so I figured I'd share the solution here in case it helps anyone else. 

 

The problem: GSAP interpolates between numbers, but how is it supposed to interpolate between something like "300px 250px" and "contain" (not a number)? So I whipped together a function that basically translates "contain" or "cover" into their px-based equivalents for that particular element at whatever size it is then. Once we've got it converted, it's easy to animate. 

 

//this function converts the backgroundSize of an element from "cover" or "contain" or "auto" into px-based dimensions. To set it immediately, pass true as the 2nd parameter.
function getBGSize(element, setInPx) {
    var e = (typeof(element) === "string") ? document.querySelector(element) : element,
            cs = window.getComputedStyle(e),
            imageUrl = cs.backgroundImage,
            size = cs.backgroundSize,
            image, w, h, iw, ih, ew, eh, ratio;
    if (imageUrl && !/\d/g.test(size)) {
        image = new Image();
        image.setAttribute("src", imageUrl.replace(/(^url\("|^url\('|^url\(|"\)$|'\)$|\)$)/gi, "")); //remove any url() wrapper. Note: some browsers include quotes, some don't.
        iw = image.naturalWidth;
        ih = image.naturalHeight;
        ratio = iw / ih;
        ew = e.offsetWidth;
        eh = e.offsetHeight;
        if (!iw || !ih) {
            console.log("getBGSize() failed; image hasn't loaded yet.");
        }
        if (size === "cover" || size === "contain") {
            if ((size === "cover") === (iw / ew > ih / eh)) {
                h = eh;
                w = eh * ratio;
            } else {
                w = ew;
                h = ew / ratio;    
            }
        } else { //"auto"
            w = iw;
            h = ih;
        }
        size = Math.ceil(w) + "px " + Math.ceil(h) + "px";
        if (setInPx) {
            e.style.backgroundSize = size;
        }
    }
    return size;
}

 

The only catch is that the image must be already loaded, otherwise it's impossible to figure out the native dimensions of the image (aspect ratio). 

 

While it's technically possible to add this functionality into CSSPlugin, it didn't seem advisable because it eats up a fair amount of kb and it's EXTREMELY uncommon for folks to want to animate to/from a background-size of cover or contain. So maybe 0.0001% of the audience would benefit but 100% would pay the kb price. Didn't seem worthwhile, so a helper function like this struck me as more appropriate. Feel free to chime in if you disagree. 

 

Happy tweening!

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

  • Like 4
Link to comment
Share on other sites

There goes @GreenSock again -- GreenShocking the community by whipping up new functions and dropping them into the forum like it's nothing. ;)

 

I can honestly say I've never even thought about animating from contain to cover, but this is pretty darn cool. 

:)

 

  • Like 4
Link to comment
Share on other sites

10 hours ago, GreenSock said:

While it's technically possible to add this functionality into CSSPlugin, it didn't seem advisable because it eats up a fair amount of kb and it's EXTREMELY uncommon for folks to want to animate to/from a background-size of cover or contain. So maybe 0.0001% of the audience would benefit but 100% would pay the kb price. Didn't seem worthwhile, so a helper function like this struck me as more appropriate. Feel free to chime in if you disagree. 

 

It's a hard choice. I know people are going to start asking for this functionality more. I think there are better ways of animating this, like using an image and scale, but I know a lot of people will still want to do it with backgroundSize. The CSSPlugin is already pretty big, and trying to match every CSS feature, while probably technically possible for the most part, would just make the plugin even bigger. 

 

Maybe this would be better off as a utility. This is a very common problem for canvas developers too. I can't tell you how many helpers libraries I see like this.

https://github.com/kittykatattack/scaleToWindow

 

The math is still the same.

  • Like 5
Link to comment
Share on other sites

15 hours ago, GreenSock said:

So maybe 0.0001% of the audience would benefit

 

I'm honestly curious ... what are those 0.0001% doing that requires scaling the background from `contain` or `cover` to a fixed/relative size? Are they looking for the tiling that occurs when either background dimension is less than the size of the element it's applied to and the background-image is set to repeat?

  • Like 1
Link to comment
Share on other sites

Join the Slack - Animation at Work and you can see where the question came from. It was posted in the #gsap channel.

http://damp-lake-50659.herokuapp.com/

 

But I don't think the repeat was really part of the question. That's just what the demo had in place when Jack forked it. I think what people are trying to do is more of lightbox effect. Click on small image, and make it fill a larger area.

  • Like 2
Link to comment
Share on other sites

OK, I see what dunkie was getting at ... wanting to do a .set('.something', {backgroundSize: 'cover'}) ...which @GreenSock addressed with a GSAP update! (man is Jack quick!!)

 

Back to the wanting an image to scale up to occupy a bigger space (which I definitely see the need for :) ) ... I've always found it super easy to apply the image background with cover ... but tween the element's size -- and perhaps within a wrapper so it doesn't mess with the document flow -- and let CSS worry about the actual sizing of the background. Like this (a perfectly hideous example :) )

 

See the Pen pLOdvx by sgorneau (@sgorneau) on CodePen

 

Or like this in another thread that I chimed in on

 

See the Pen JLKbBm by sgorneau (@sgorneau) on CodePen

 

But I might be missing a more specific use case. I'm not dismissing the solution :) ... just honestly curious where people would need to actually tween a background image.

  • Like 4
Link to comment
Share on other sites

I would echo Blake's advice above about joining the Animation At Work slack and following these channels

http://damp-lake-50659.herokuapp.com/

 

#GSAP

#general

#codepen

#uianimation

#svg

 

There are definitely some interesting conversations going on and you get exposed to some ideas and techniques that you wouldn't necessarily stumble into elsewhere. 

 

At first we were worried that the #GSAP channel would turn into a support nightmare (with people expecting instant "live-chat" answers from Jack or myself) but so far it really hasn't been too bad. Just a few questions per week that are often answered by other people in a reasonable amount of time. 

  • Like 5
Link to comment
Share on other sites

Hi @Shaun Gorneau,

 

26 minutes ago, Shaun Gorneau said:

But I might be missing a more specific use case. I'm not dismissing the solution :) ... just honestly curious where people would need to actually tween a background image.

 

You can tween a background image when animating image sprites or doing say a ken burns type of effect for an image using background-size. But usually the limitation falls short due to some browsers not doing sub-pixel rendering. For example, i used to be able to force autoRound to false and I would see Firefox and or Chrome animate on a sub-pixel level for values of background-size and background-position without pixel snapping, even though it would not render with GPU. But now it seems to be intermittent in honoring autoRound:false.

 

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

 

I prefer animating transforms like scale for images like @OSUblake said above, but there are a lot of uses for animating a background image, it just depends what works for each project.

 

Thanks for this solution @GreenSock Jack!

 

Thanks guys i just signed up for that Slack - Animation at Work.

 

Just my two bits :)

  • Like 4
Link to comment
Share on other sites

  • 3 years later...

Can this method be applied to animate a background image size from a percentage to cover?

 

So from

background-size: 150% auto;

to

background-size: cover;

 

Using the original function doesn't seem to work as configured: 

See the Pen ExmjWRW by ChrisBup (@ChrisBup) on CodePen

Link to comment
Share on other sites

Doesn't look like it, 

it's animating but it's not respecting the initial cover size

See the Pen 9f61045d39ed7ffb10b89ad9495a4dfe?editors=1111 by cassie-codes (@cassie-codes) on CodePen



I'd probably steer clear of animating background images if possible though - it's likely to be a lot more janky than animating with transforms.

If you really need it maybe @GreenSock would update the helper?

Link to comment
Share on other sites

I agree with @Cassie - it's almost always better to animate an actual image with scaleX/scaleY/x/y but I went ahead and enhanced the helper function to have several new features.

 

You can define a config object where you can set size, nativeWidth, and/or nativeHeight. It handles percentage-based values too. 

 

Here's a fork with that function in place: 

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

  • Like 4
Link to comment
Share on other sites

  • 1 month later...

Thanks! For anyone interested down the line, I made a slight modification just to prevent aspect ratio distortion when initial width or height are defined as auto instead of a percentage:

 

See the Pen oNwXewJ by ChrisBup (@ChrisBup) on CodePen

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