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.

Pure CSS MIT licensed
Live Demo Open in tab
Open in playground

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>
.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 plain color renders.
  • Add a third tier for very old browsers by placing a hex colour in a separate declaration block above the @supports block, before even the variable-based color.
  • 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 @supports block tests for the -webkit-background-clip: text declaration 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 @supports condition 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 @supports in older IE versions — IE does not implement @supports at all, which means the block is skipped entirely and the plain color fallback is used. This is the correct and desired behaviour.

Browser support

ChromeSafariFirefoxEdge
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+).

Search CodeFronts

Loading…