It was a lovely day on the internet when someone asked how to CSS animated gradient text like ChatGPT’s “Searching the web” and promptly got an answer saying “Have you tried asking ChatGPT? Here’s what it told me!” – well, maybe not these exact words, but at least it rhymes.
Both the question and this answer have since been deleted. But we still have the chat link that got posted in the answer and we’re going to look into it.
Screenshot of ChatGPT Generated Code

This is the code that ChatGPT spat out in text format:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Text Color Loading Animation</title>
<style>
body {
background-color: #111;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.loading-text {
font-size: 3rem;
font-weight: bold;
background: linear-gradient(90deg, #00f, #0ff, #00f);
background-size: 200% auto;
background-clip: text;
-webkit-background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
animation: shimmer 2s linear infinite;
}
@keyframes shimmer {
0% {
background-position: -100% 0;
}
100% {
background-position: 100% 0;
}
}
</style>
</head>
<body>
<div class="loading-text">Loading...</div>
</body>
</html>
Code language: HTML, XML (xml)
Now you may be thinking: what’s the problem with this code, anyway? If you copy-paste into CodePen, it does produce the desired result, doesn’t it?
Well, we also get the exact same result if we replace this CSS:
.loading-text {
font-size: 3rem;
font-weight: bold;
background: linear-gradient(90deg, #00f, #0ff, #00f);
background-size: 200% auto;
background-clip: text;
-webkit-background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
animation: shimmer 2s linear infinite;
}
@keyframes shimmer {
0% {
background-position: -100% 0;
}
100% {
background-position: 100% 0;
}
}
Code language: CSS (css)
with this CSS:
.loading-text {
font-size: 3rem;
font-weight: bold;
background: linear-gradient(90deg, #00f, #0ff, #00f) -100%/ 200%;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: shimmer 2s linear infinite;
}
@keyframes shimmer {
to {
background-position: 100%;
}
}
Code language: CSS (css)
You might think the ChatGPT solution includes some fallbacks that maybe make it work in more browsers. You’d be wrong. There are exactly zero browsers in which the ChatGPT solution isn’t broken, but the alternative above is. Zero! Not a single one. In all of the (very old) browsers where the alternative above breaks, the ChatGPT solution breaks too.
The history of gradient text solutions and what ChatGPT gets wrong
Let’s go some 15 years back in time. I discovered CSS in August 2009, just as it was getting new shiny features like transforms and gradients. One of the first tricks I came across online in early 2010 was precisely this — creating image text in general and CSS gradient text in particular.
The declaration I ditched completely from what ChatGPT generated was:
-webkit-text-fill-color: transparent;
Code language: CSS (css)
This answer only included -webkit-text-fill-color
, though I’ve seen versions of this circulating online that use:
-webkit-text-fill-color: transparent;
text-fill-color: transparent;
Code language: CSS (css)
There is no such thing as text-fill-color
. There isn’t even a standard spec for it. It’s just something that was implemented in WebKit with a prefix almost 2 decades ago and then became used enough on the web that other browsers had to support it too. With the -webkit-
prefix. So the prefixed version is the only one that has ever been implemented in any browser.
While WebKit introduced this property alongside -webkit-text-stroke
, its usage would end up far exceeding that of -webkit-text-stroke
. This is something that started about 15 years ago when -webkit-text-fill-color
became a common tactic for making text transparent only in WebKit browsers. Precisely for image text in general and then a lot more often for gradient text in particular.
At the time, clipping backgrounds to text
was only supported in WebKit browsers via the (back then) non-standard -webkit-background-clip: text
. If we wanted to get a visible gradient text this way, we had to be able to see through the actual text on top of the clipped background
. Problem was, back in 2010, if we set color
to transparent
, then we’d get:
- Gradient text as desired in browsers supporting both
-webkit-background-clip: text
and CSS gradients - No visible text and a gradient rectangle in browsers supporting CSS gradients, but not
-webkit-background-clip: text
(in 2010, this would have been the case for Firefox) - Nothing visible at all in browsers not supporting CSS gradients (remember the first IE version to support CSS gradients was IE10, which only came out in 2012; plus Opera still had its own engine back then and wouldn’t get CSS gradients for another year)

So given the only browsers we could get gradient text in at the time were WebKit browsers, it made sense to restrict both setting a gradient background
and making the text transparent
to WebKit browsers. At the time, all gradients were prefixed, so that made the first part easier. For the second part, the solution was to use -webkit-text-fill-color
to basically override color
just for WebKit browsers.
So to get an aqua to blue gradient text with a decent in-between blue text fallback in non-supporting browsers, the code we had to write in 2010 looked like this:
color: #07f;
background:
-webkit-gradient(linear, 0 0, 100% 0,
color-stop(0, #0ff), color-stop(1, #00f));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent
Code language: CSS (css)
Note that at the time, this was seen as a temporary WebKit-only solution, as other options for getting such gradient text were being discussed. The “temporary” solution stuck, I guess. And so it’s now in the spec.
And yes, that is a different gradient syntax (which, by the way, is still supported to this day in Chrome). The syntax for CSS gradients went through multiple iterations. After this one, we had another -webkit-
prefixed version, a lot more similar to what we have today, but still not the same. If you’re curious, you can see a bit more about the support timeline in my 10 year old rant about using gradient generators without understanding the code they spit out and without having a clue how much of it is really necessary. Because before we had AI chatbots spitting out too much needless CSS for the desired result, we had all these CSS3 generators doing pretty much the same! Like a song says, oh, it was different… and yet the same!
Using -webkit-text-fill-color
to override color
just for WebKit browsers, we got:

Better, I guess, but not ideal.
Since support for -webkit-text-fill-color
came before for CSS gradients, that left a gap where the text would be made transparent, but there would be no gradient to be clipped to (making the support status for -webkit-background-clip: text
irrelevant). In this case, there would be no visible text and no gradient… just nothing but empty space.
I first thought that anyone who’d be using one of these browsers that would always be the first to support new and shiny things would also care about keeping them updated, right? Right?
Wrong! Some months later, I went to a job interview. I’ve always been a show-off, I’m like a fish in the water when live coding, so I jumped on the chance to actually get in front of a computer and impress with all the cool things I could do thanks to the new CSS features. They were using a Chrome version that was quite a bit behind the then current one. CSS gradients did not work.
I started using Modernizr to test for CSS gradient support after that. We didn’t have @supports
back then, so Modernizr was the way to go for many years.
Then there was the Android problem – CSS gradients being supported, but not -webkit-background-clip: text
, though support tests returned false positives. Since I didn’t have a smartphone and I don’t think I even knew anyone who had one at the time, I couldn’t test if any fix found on the internet would work and I don’t recall anyone ever complaining, so I confess I never even bothered with trying to cover this case.
Then things started to get even funnier.
In 2011, WebKit browsers started supporting a newer, different gradient syntax. Still with a prefix, still different from the standard one. Most notably, angles were going in the opposite direction and the gradient start was offset by 90°
relative to the current version, meaning the 0°
gradient start was taken to be at 3 o’clock, rather than at 12 o’clock like in the case of the current standard one.
This really caught on. Prefixes were meant to solve a problem, but a lot of developers skipped reading the instructions on the box, so they wrote code with either too many prefixed versions of the same properties or, more commonly, not enough… usually just the WebKit one. Which meant other browsers started considering supporting the -webkit-
prefix too.
There was a lot written about it at the time, but basically what this meant was that Opera first implemented -webkit-
prefixes in 2012 and then switched away from Presto altogether a year later, at around the same time Blink was announced. Another year later, IE added the -webkit-
prefix too. This would carry over to Edge and then Edge would also move to Blink. And then in 2015–2016, Firefox also implemented some non-standard -webkit-
prefixed properties and mapped some other -webkit-
prefixed properties to their -moz-
or standard equivalents.
What this meant was that for a while, we had support for -webkit-
prefixed gradients in non-WebKit browsers… but not support for -webkit-text-fill-color
, -webkit-background-clip: text
, so the following code:
color: #07f;
background: -webkit-linear-gradient(left, #0ff, #00f);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent
Code language: CSS (css)
would for example produce a mid blue text on an aqua to blue gradient rectangle in Opera in-between starting to support the -webkit-
prefix and switching to Blink. Not very readable, right?

So the solution for that was to add another fully transparent -o-
prefixed gradient after the -webkit-
one:
color: #07f;
background: -webkit-linear-gradient(left, #0ff, #00f);
background: -o-linear-gradient(transparent, transparent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent
Code language: CSS (css)
Quite the mess indeed.
Since 2016, all browsers except Opera Mini have supported clipping backgrounds to text
. Given the lack of support for clipping backgrounds to text
was why we avoided setting color
to transparent
, what’s the point of still using -webkit-text-fill-color
now?
You might say support. Indeed, there are people stuck on old browsers without the option to update because they are stuck on old operating systems which they cannot upgrade because of the age of hardware. I live in Romania and not only do I know people still using Windows XP on computers from the ’90s, I have seen that some public institutions still use Windows XP too. Newer browser versions don’t work there… but even so, the last browser versions that support Windows XP all support clipping backgrounds to text
. And with automatic updates, all I’ve seen have been warnings about being unable to update to a newer version, not browsers stuck even further back.
Even if they were that far back, the ChatGPT solution sets color
to transparent
alongside -webkit-text-fill-color
. The whole point of using -webkit-text-fill-color
before clipping backgrounds to text
became cross-browser was to avoid setting color
to transparent
, which ChatGPT isn’t doing because it’s dumping that declaration in there too. So it’s not improving support, it’s just adding redundant code. Or breaking the solution for a problem that had become obsolete over half a decade before ChatGPT was launched. Whichever you prefer.
In any case, the ChatGPT code is what we call “struţocămilă” in Romanian – an impossible animal that’s half ostrich, half camel.

Not to mention today we have something far better for handling such situations: @supports
!
I get the extending support argument for not setting background-clip: text
in the shorthand or even unprefixed. Though now supported unprefixed and in the shorthand in the current versions of all major desktop and mobile browsers, support doesn’t extend to the last browser versions on Windows XP, 7 or 8.
That being said, if manually including both the prefixed and standard versions of a property, please always include the unprefixed one last. There are very rare situations where having the prefixed version of a property override the standard one might make sense for getting around some weird bug, but that’s definitely not the case here.
background-size
On Another thing you may have noticed is the ChatGPT solution sets background-size
separately, not in the shorthand and that it uses two values, not just one, the second one being auto.
There is a historical (although also completely pointless today) reason behind this too. 15 years ago, when we first got this pure CSS gradient text technique, most browsers didn’t yet support setting background-size
in the shorthand. So it was set separately. But that has not been an issue for over a decade.
Another issue with background-size
was that initially, WebKit browsers implemented an earlier draft of the spec where a missing second value was taken to be equal to the first value, rather than auto
, which in the case of gradients means the height of the box specified by background-origin
(by default the padding-box
). However, in the case of a horizontal gradient like the one we have here, the second background-size
value is completely irrelevant, regardless of the background-position
. Whether it’s 200%
(duplicating the first value) or auto
(100%
of the padding-box
height in this case), the visual result is always exactly the same for horizontal gradients.
So there is no reason why setting it in the shorthand with a single value wouldn’t produce the exact same result. And that has been the case for over a decade.
Finessing things
Similar to how we can omit the second background-size
value, we can also omit it for background-position
. The default is 50%
, but any other value produces the exact same result in the case of any gradient covering the entire height of the background-origin
box. And in the case of a horizontal gradient like we have here, it wouldn’t matter even if we had a different background-size
height.
We can also easily omit one of the two end keyframes and set its background-position
in the shorthand. Then the missing end keyframe gets generated out of there. This is not a new feature, I’ve been using this for over a decade.
Then I’m not a fan of those body
styles. Firstly, without zeroing its default margin
, setting its height to 100vh
creates a scrollbar. Secondly, it can also be problematic even when setting margin: 0
. Just don’t do it and do this instead, it has better support than dvh
:
html, body { display: grid }
html { height: 100% }
body { background: #222 }
.loading-text { place-self: center }
Code language: CSS (css)
Finally, default fonts might be ugly, so let’s go for a prettier one. We could also make it scale with the viewport within reasonable limits.
font: 900 clamp(2em, 10vw, 10em) exo, sans-serif
Code language: CSS (css)
Here’s a CodePen demo:
This is not just ChatGPT
ChatGPT is in the title because it was what got used in this case. But this “dump in old popular solutions and sprinkle in some modern CSS to create a grotesque hybrid” is not unique to ChatGPT.
I saw Gemini spit out this monstruosity (that doesn’t even produce the desired result) just a day earlier:

It makes sense. Older solutions have had more time to become more popular and they’re often at the top in search results too. But that doesn’t necessarily mean they’re still the best choice today. At least when you’re looking at an article or a Stack Overflow answer, you can check the date. An AI solution might link to resources (and in one instance, I discovered it was my own 12-year old, obsolete StackOverflow answer that was being referenced), but if it doesn’t or if you don’t check the resources, then you can never know just how outdated a technique might be. Or how badly it got messed up on the way.