CSS Gradient Generator — Banding on Low-End Android

webdev css gradient performance tools

The hero looks buttery on your MacBook. On a $150 Android, the sky gradient turns into stripes. That is banding — not “user doesn’t get design.” Soft blends need deliberate engineering when panels only show so many shades.

What banding is

When the display cannot represent every intermediate color between two stops, adjacent pixels snap to the same value and form stripes. Long, low-contrast blends (dark navy → slightly lighter navy) are prime suspects.

FactorEffect
6-bit / poor dithering panelsFewer distinct shades
Long pixel distanceMore steps needed
Low contrast blendSteps become obvious

Sketch stops in a CSS gradient generator, then verify on a real low-end handset — not only DevTools device mode.

Linear gradient basics

.hero {
  background: linear-gradient(
    165deg,
    #0b1220 0%,
    #152238 45%,
    #1e3a5f 100%
  );
}

Prefer deg when matching Figma. Put important hue shifts where the eye rests. Keep alpha gradients mindful of the underlying color.

Anti-banding tactics

  1. Shorten the blend — soft cover 40% of the viewport instead of 100% when possible.
  2. Whisper mid stops — shape the curve; do not spam twenty random stops.
  3. Micro-noise overlay — 2–4% opacity repeating noise breaks false contours without a full-screen canvas.
  4. Slightly higher contrast if brand allows.
  5. Test in a dark room on device — banding loves OLED + dark UI.
.card-glow {
  background:
    radial-gradient(120% 80% at 10% 0%, rgb(56 189 248 / 0.18), transparent 50%),
    linear-gradient(180deg, #0f172a, #020617);
}

Multi-layer backgrounds beat one heroic 8-stop monster when debugging. CSS mesh gradients still need a linear/radial fallback.

Matching Figma and dark mode

Export angle and stop percentages, convert to your token color space, compare a device screenshot to Figma, and accept a 1–2% stop tweak when hardware bands. Define --hero-grad-light and --hero-grad-dark separately — do not invert stops blindly.

Place text over the darkest/lightest stable region or add a scrim. Contrast-checking one midpoint hex is not enough when the background changes behind every glyph.

Performance and a11y

Animate opacity/transform of layers, not gradient stops every frame. Avoid giant filter: blur on gradient layers. Prioritize anti-banding on large heroes users stare at — not a 32px badge. Offer a solid fallback when prefers-reduced-transparency: reduce matches.

QA before merge: mid-range Android photo, both themes, text contrast on the loudest region. Smooth on flagship is table stakes; smooth on budget Android is the craft.

Repeating and conic accents

repeating-linear-gradient is great for subtle stripes and danger tape — keep contrast gentle or it becomes noisy. conic-gradient powers pie charts and angular sweeps; it bands differently than linear blends, so test it on the same cheap Android panel. For UI chrome, one soft linear wash plus a quiet radial highlight usually beats a conic rainbow behind body text.

Gradient text and clipping

background-clip: text gradient headlines look great on marketing pages and can hammer readability on busy photos. Always provide a solid color fallback and check contrast as if the gradient failed. Animate opacity of the whole headline, not the gradient stops, if you need motion.

Document the approved hero gradient as a token pair (light/dark) in the design system. Random one-off gradients in marketing PRs are how banding and contrast regressions return every campaign cycle.

Prefers-reduced-motion

Animated gradient backgrounds should respect prefers-reduced-motion. Provide a static fallback wash for users who opted out of motion so marketing pages stay comfortable.