20 CSS Text Gradient Effects 17 / 20
CSS Text Gradient Fallback for Older Browsers
A layered fallback reference with three tiers: plain color, @supports-guarded gradient, and the complete pattern for cross-browser safety.
The code
<div class="tg-17">
<div class="tg-17__doc">
<h2 class="tg-17__h">Browser Compatibility Strategy</h2>
<p class="tg-17__intro">A layered fallback ensures gradient text looks great in modern browsers and degrades gracefully in older ones — no JavaScript required.</p>
<div class="tg-17__layer-list">
<div class="tg-17__layer">
<span class="tg-17__badge tg-17__badge--1">Layer 1</span>
<div>
<strong>Solid color fallback</strong>
<p>Set a plain <code>color</code> first. Browsers that don't support <code>background-clip: text</code> will render this.</p>
<span class="tg-17__demo-text tg-17__solid">Solid Fallback</span>
</div>
</div>
<div class="tg-17__layer">
<span class="tg-17__badge tg-17__badge--2">Layer 2</span>
<div>
<strong>@supports guard</strong>
<p>Wrap gradient text rules in <code>@supports (-webkit-background-clip: text)</code> to scope them to capable browsers only.</p>
<span class="tg-17__demo-text tg-17__guarded">Guarded Gradient</span>
</div>
</div>
<div class="tg-17__layer">
<span class="tg-17__badge tg-17__badge--3">Layer 3</span>
<div>
<strong>Result in all engines</strong>
<p>Modern browsers get the gradient; IE/old Android fall back to the solid <code>color</code> — readable in both cases.</p>
<span class="tg-17__demo-text tg-17__final">Final Output</span>
</div>
</div>
</div>
</div>
</div> <div class="tg-17">
<div class="tg-17__doc">
<h2 class="tg-17__h">Browser Compatibility Strategy</h2>
<p class="tg-17__intro">A layered fallback ensures gradient text looks great in modern browsers and degrades gracefully in older ones — no JavaScript required.</p>
<div class="tg-17__layer-list">
<div class="tg-17__layer">
<span class="tg-17__badge tg-17__badge--1">Layer 1</span>
<div>
<strong>Solid color fallback</strong>
<p>Set a plain <code>color</code> first. Browsers that don't support <code>background-clip: text</code> will render this.</p>
<span class="tg-17__demo-text tg-17__solid">Solid Fallback</span>
</div>
</div>
<div class="tg-17__layer">
<span class="tg-17__badge tg-17__badge--2">Layer 2</span>
<div>
<strong>@supports guard</strong>
<p>Wrap gradient text rules in <code>@supports (-webkit-background-clip: text)</code> to scope them to capable browsers only.</p>
<span class="tg-17__demo-text tg-17__guarded">Guarded Gradient</span>
</div>
</div>
<div class="tg-17__layer">
<span class="tg-17__badge tg-17__badge--3">Layer 3</span>
<div>
<strong>Result in all engines</strong>
<p>Modern browsers get the gradient; IE/old Android fall back to the solid <code>color</code> — readable in both cases.</p>
<span class="tg-17__demo-text tg-17__final">Final Output</span>
</div>
</div>
</div>
</div>
</div>.tg-17, .tg-17 *, .tg-17 *::before, .tg-17 *::after { margin:0; padding:0; box-sizing:border-box; }
.tg-17 ::selection { background:#3b82f6; color:#fff; }
.tg-17 {
/* Picked endpoints far apart on the spectrum (cobalt → magenta) so
the gradient transition is obvious — adjacent-hue gradients
(e.g. blue→violet) read as a flat colour at smaller sizes. */
--g-a: #2563eb;
--g-b: #ec4899;
--bg: #f8fafc;
--text: #0f172a;
--muted: #64748b;
--border: #e2e8f0;
--surface: #ffffff;
font-family: system-ui, -apple-system, sans-serif;
background: var(--bg);
min-height: 100vh;
padding: 44px 28px;
display: flex;
align-items: flex-start;
justify-content: center;
}
.tg-17__doc { max-width: 640px; width: 100%; }
.tg-17__h {
font-size: 1.5rem;
font-weight: 800;
color: var(--text);
letter-spacing: -.02em;
margin-bottom: 10px;
}
.tg-17__intro {
color: var(--muted);
font-size: .9rem;
line-height: 1.7;
margin-bottom: 28px;
max-width: 540px;
}
.tg-17__layer-list { display: flex; flex-direction: column; gap: 14px; }
.tg-17__layer {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px 20px 20px 16px;
display: flex;
gap: 16px;
align-items: flex-start;
}
.tg-17__layer strong { display: block; font-size: .9375rem; color: var(--text); margin-bottom: 4px; }
.tg-17__layer p { font-size: .8125rem; color: var(--muted); line-height: 1.55; margin-bottom: 10px; }
.tg-17__layer code {
background: #f1f5f9;
border-radius: 3px;
padding: 1px 5px;
font-size: .78em;
color: var(--g-b);
}
.tg-17__badge {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: .65rem;
font-weight: 700;
letter-spacing: .06em;
border-radius: 6px;
padding: 4px 8px;
flex-shrink: 0;
margin-top: 2px;
white-space: nowrap;
}
.tg-17__badge--1 { background: #fef9c3; color: #854d0e; }
.tg-17__badge--2 { background: #dbeafe; color: #1e40af; }
.tg-17__badge--3 { background: #f3e8ff; color: #6b21a8; }
/* Demo text: Layer 1 — solid fallback colour only */
.tg-17__solid {
font-size: 2.2rem;
font-weight: 800;
color: var(--g-a); /* Fallback: plain colour */
display: block;
letter-spacing: -.02em;
}
/* Layer 2 — @supports guard */
.tg-17__guarded {
font-size: 2.2rem;
font-weight: 800;
color: var(--g-b); /* Fallback */
display: block;
letter-spacing: -.02em;
}
@supports (-webkit-background-clip: text) or (background-clip: text) {
.tg-17__guarded {
/* Use background-image (not the shorthand) so background-clip
below survives. The shorthand would reset background-clip to
border-box. */
background-image: linear-gradient(90deg, var(--g-a), var(--g-b));
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
display: inline-block;
padding: 0 .05em .1em;
}
}
/* Layer 3 — complete pattern with @supports */
.tg-17__final {
font-size: 2.2rem;
font-weight: 800;
color: var(--g-a);
display: block;
letter-spacing: -.02em;
}
@supports (-webkit-background-clip: text) or (background-clip: text) {
.tg-17__final {
background-image: linear-gradient(90deg, var(--g-a) 0%, var(--g-b) 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
display: inline-block;
padding: 0 .05em .1em;
}
}
@media (prefers-reduced-motion: reduce) {} .tg-17, .tg-17 *, .tg-17 *::before, .tg-17 *::after { margin:0; padding:0; box-sizing:border-box; }
.tg-17 ::selection { background:#3b82f6; color:#fff; }
.tg-17 {
/* Picked endpoints far apart on the spectrum (cobalt → magenta) so
the gradient transition is obvious — adjacent-hue gradients
(e.g. blue→violet) read as a flat colour at smaller sizes. */
--g-a: #2563eb;
--g-b: #ec4899;
--bg: #f8fafc;
--text: #0f172a;
--muted: #64748b;
--border: #e2e8f0;
--surface: #ffffff;
font-family: system-ui, -apple-system, sans-serif;
background: var(--bg);
min-height: 100vh;
padding: 44px 28px;
display: flex;
align-items: flex-start;
justify-content: center;
}
.tg-17__doc { max-width: 640px; width: 100%; }
.tg-17__h {
font-size: 1.5rem;
font-weight: 800;
color: var(--text);
letter-spacing: -.02em;
margin-bottom: 10px;
}
.tg-17__intro {
color: var(--muted);
font-size: .9rem;
line-height: 1.7;
margin-bottom: 28px;
max-width: 540px;
}
.tg-17__layer-list { display: flex; flex-direction: column; gap: 14px; }
.tg-17__layer {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px 20px 20px 16px;
display: flex;
gap: 16px;
align-items: flex-start;
}
.tg-17__layer strong { display: block; font-size: .9375rem; color: var(--text); margin-bottom: 4px; }
.tg-17__layer p { font-size: .8125rem; color: var(--muted); line-height: 1.55; margin-bottom: 10px; }
.tg-17__layer code {
background: #f1f5f9;
border-radius: 3px;
padding: 1px 5px;
font-size: .78em;
color: var(--g-b);
}
.tg-17__badge {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: .65rem;
font-weight: 700;
letter-spacing: .06em;
border-radius: 6px;
padding: 4px 8px;
flex-shrink: 0;
margin-top: 2px;
white-space: nowrap;
}
.tg-17__badge--1 { background: #fef9c3; color: #854d0e; }
.tg-17__badge--2 { background: #dbeafe; color: #1e40af; }
.tg-17__badge--3 { background: #f3e8ff; color: #6b21a8; }
/* Demo text: Layer 1 — solid fallback colour only */
.tg-17__solid {
font-size: 2.2rem;
font-weight: 800;
color: var(--g-a); /* Fallback: plain colour */
display: block;
letter-spacing: -.02em;
}
/* Layer 2 — @supports guard */
.tg-17__guarded {
font-size: 2.2rem;
font-weight: 800;
color: var(--g-b); /* Fallback */
display: block;
letter-spacing: -.02em;
}
@supports (-webkit-background-clip: text) or (background-clip: text) {
.tg-17__guarded {
/* Use background-image (not the shorthand) so background-clip
below survives. The shorthand would reset background-clip to
border-box. */
background-image: linear-gradient(90deg, var(--g-a), var(--g-b));
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
display: inline-block;
padding: 0 .05em .1em;
}
}
/* Layer 3 — complete pattern with @supports */
.tg-17__final {
font-size: 2.2rem;
font-weight: 800;
color: var(--g-a);
display: block;
letter-spacing: -.02em;
}
@supports (-webkit-background-clip: text) or (background-clip: text) {
.tg-17__final {
background-image: linear-gradient(90deg, var(--g-a) 0%, var(--g-b) 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
display: inline-block;
padding: 0 .05em .1em;
}
}
@media (prefers-reduced-motion: reduce) {}How this works
The three-layer fallback works from most-compatible to most-capable. First a plain color is declared — every browser understands this. Then an @supports (-webkit-background-clip: text) or (background-clip: text) block wraps the gradient declarations, meaning only browsers that actually implement the feature will apply them. This prevents older engines from partially applying declarations and breaking the display.
Inside the @supports block, both the -webkit- prefixed and unprefixed forms of background-clip are declared, as well as -webkit-text-fill-color: transparent alongside color: transparent. The color: transparent is redundant in capable browsers but ensures the text disappears even if -webkit-text-fill-color is not supported, which can happen in some uncommon engine versions.
Customize
- Test the fallback by temporarily renaming
@supports (-webkit-background-clip: text)to something invalid — all gradient rules will be skipped and the plaincolorrenders. - Add a third tier for very old browsers by placing a hex colour in a separate declaration block above the
@supportsblock, before even the variable-basedcolor. - Extend the pattern to icon SVGs using
@supports (background-clip: text)to conditionally apply gradient fills to inline SVG text elements that fallback to a solid stroke. - Document the technique in your design system by using this demo's three-layer card layout as a reference component that QA teams can load in any target browser to verify gradient rendering.
- Add
@supports not (-webkit-background-clip: text)to show a polished alternative style in unsupported browsers — e.g. an underline decoration or a contrasting font weight.
Watch out for
- The
@supportsblock tests for the-webkit-background-clip: textdeclaration specifically. Some browsers may pass this test but still render incorrectly — always complement the @supports check with a visual QA step in the actual target browsers. - In production, avoid using CSS custom properties (
var(--colour)) inside the@supportscondition string — the condition tests the raw property-value pair, and variable references inside the test string may not resolve in all browsers. - Do not rely on
@supportsin older IE versions — IE does not implement@supportsat all, which means the block is skipped entirely and the plaincolorfallback is used. This is the correct and desired behaviour.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 28+ | 9+ | 22+ | 28+ |
@supports has excellent coverage; the gradient text declarations inside it require the same engine support as the standalone technique (Chrome 69+, Safari 12.1+, Firefox 83+).