Jump to content
Search Community

GSAP 3 animating CSS gradients

mystrdat2 test
Moderator Tag

Recommended Posts

That isn't actually a bug - it's due to the fact that the browser reports the computed value in an odd way (without the degrees value at all when it's 180deg). Try this:

console.log(getComputedStyle(document.querySelector("div")).backgroundImage);

That reports it as: 

"linear-gradient(rgb(254, 176, 42) 0%, rgb(253, 150, 34) 100%)"

So when GSAP tries to match up the complex string values, it always goes in order from left to right, finding the numeric values and colors. So when you try to animate between these: 

start: "linear-gradient(rgb(254, 176, 42) 0%, rgb(253, 150, 34) 100%)"
end:   "linear-gradient(180deg, rgba(254,176,42,1) 0%, rgba(253,150,34,1) 100%)"

It wouldn't know what to do because there's a mis-matched number (and type) of values. See the issue? 

 

"But I'm feeding in the start value, so why doesn't it just use that?" Because the "from" values DO get applied right away, like a gsap.set() and then the tween still needs to read the current values (at that time) and the browser has the same issue - it omits the deg value. 

 

You could solve this in various different ways. One is to create a generic object that stores the raw value, and tween that, applying it to your target in an onUpdate: 

let gradient = {value: 'linear-gradient(180deg, rgba(254,176,42,1) 0%, rgba(253,150,34,1) 100%)'},
	target = document.querySelector("div");
gsap.to(gradient, {
	value: 'linear-gradient(180deg, rgba(254,210,51,1) 0%, rgba(253,155,36,1) 100%)',
	duration: 10,
	repeat: 3,
	yoyo: true,
	onUpdate: () => target.style.backgroundImage = gradient.value
});

An even easier and more reusable way to solve this is to create a basic plugin. Here I have it control a custom "gradient" property which just affects the backgroundImage internally: 

// assumes you'll always define things with a "deg" value, and it'll get applied to backgroundImage
gsap.registerPlugin({
	name: "gradient",
	init(target, value) {
		let forceDeg = value => ~value.indexOf("deg") ? value : (value = value.split("(")) && value.shift() + "(180deg, " + value.join("(");
		this.add(target.style, "backgroundImage", forceDeg(window.getComputedStyle(target).backgroundImage + ""), forceDeg(value));
	}
});

Then, after that plugin is registered, you could use it in any tween like this: 

gsap.to("div", {
	gradient: "linear-gradient(180deg, rgba(254,210,51,1) 0%, rgba(253,155,36,1) 100%)",
	duration: 10,
	repeat: 3,
	yoyo: true
});

There are a bunch of other ways you could solve this too, but I don't want to overwhelm you :)

 

Why doesn't GSAP automatically handle this conversion internally, like in CSSPlugin? Because in GSAP v3, we intentionally aimed to slim things down and not try to shove a ton of extra code in there for every edge case. Linear gradients have a huge range of formatting options, so it'd be very complex to handle every possible permutation of the syntax, especially when such a tiny fraction of our users would ever actually use it. So in edge cases like this, we thought it's better to just handle it in one of the ways mentioned above so that the core can remain efficient and small. 

 

Does that clear things up? 

  • Like 6
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.
×
×
  • Create New...