Skip to content

Gradient Text Turned Into a Color Box: the Shorthand That Resets

Adityo Guni Waluyo

A theme override using the background shorthand silently reset background-clip:text from the base rule, so gradient text rendered as a solid color box.

TL;DR

A CSS background shorthand silently reset background-clip:text, turning gradient text into a solid color box. Swapping to the background-image longhand fixed it, since the base rule's clipping stayed intact. Lesson: the background shorthand resets what you don't set, so per-theme visual checks are now mandatory before pushing.

Gradient Text Became a Solid Color Box

Two minutes after pushing the light mode variant commit, I opened staging and saw the brand name in the header had become a solid gradient box. No longer gradient text, but an actual box of color, green to purple, filling the area that used to be just lettering.

My first suspicion was a wrong gradient stop. Maybe a hex color got copied incompletely. Opened DevTools, checked the computed style background-image: the gradient was correct, three colors straight at 90 degrees. Exactly what I wanted. But what showed on screen was still a box.

The Keyword That Silently Resets

The funny thing about this kind of bug is that it never throws an error. No console warning, no red build. The gradient itself renders perfectly fine, only its "canvas" has the wrong size. Everything looks normal as long as you don't compare the result with the original design intent. Only after digging deeper did I find the problem. I wrote the light variant using the background: linear-gradient(...) shorthand. And that's the trap.

MDN spells the rule out explicitly: component properties not set in a background shorthand declaration automatically fall back to their default values [4]. Meaning the setting that clips to the text shape, already set in the base rule, gets reset straight to its initial value, a border box. The gradient is still there, but it's no longer clipped to the text shape, so it becomes a box [5].

The small proof shows up in the computed style panel: after the shorthand runs, the background clipping property on that element changes to border box, its initial value per MDN [5]. Meaning the browser isn't "broken", it's executing the shorthand contract exactly: start from zero, fill in what was sent, default the rest. The base rule writes each part separately: the gradient image in one declaration, the text-shape clipping in another. Everything works. The moment I overrode it with a one-line shorthand in the light override, both of those properties vanished without a peep.

The change in commit 366618c just swapped the shorthand for the longhand. One line: background-image: linear-gradient(...) replacing background: linear-gradient(...). The background-clip:text from the base rule stays alive because it never got reset.

This moment also exposed a weak spot in my process: theme changes are visual, and the cheapest visual test is still my own eyes. Same as when the transparent cards vanished in light mode, this bug didn't turn the build red, didn't throw a console error, the page looked "done". Only the rendered result changed, and that only gets caught if someone deliberately looks. Per-theme screengrabs are now a fixed step before pushing a restyle. What made me shake my head was the timing. The light variant was introduced in commit d3a62fc, went straight to staging, and lived there for roughly two minutes before the fix landed. Two minutes was enough for me to screenshot, get confused, and start diagnosing. Thankfully staging is exactly the place meant to look ugly. If this variant had gone straight to production, that gradient box would have greeted readers before I even noticed.

So the difference is visible, here's what the two versions looked like in the same file:

/* broken version: shorthand resets background-clip from the base rule */
.light .text-gradient-tri {
  background: linear-gradient(90deg, #1a7f37, #0969da, #8250df);
}

/* fixed version: longhand, the base rule's background-clip:text stays alive */
.light .text-gradient-tri {
  background-image: linear-gradient(90deg, #1a7f37, #0969da, #8250df);
}

I did consider another option: adding background-clip:text directly into the light mode override so the declaration is complete. That closes the problem too, but it makes two places spell the same thing, and later there'd be two places to remember whenever the base rule changes. Removing the cause instead of patching the symptom keeps the file lean. My personal rule from now on: if I only want to change the background image in a theme override, use background-image directly. The background shorthand is indeed complete, but its completeness is exactly the risk: it doesn't just add, it also resets [8]. And in CSS, a reset you didn't notice is the hardest kind of bug to hunt down, because the running code never lies, only our intent differs from the contract the browser reads.

Sources

Related articles