Why Color Ramps Lose Detail in the Darks — and How Interpolation Method Fixes It
Open any palette built with a standard tool and look at the darkest three or four shades. Chances are they look nearly identical — near-black variants that are barely distinguishable from each other, and from pure black.
This isn't a subjective observation. It's a measurable, predictable failure caused by the color space used to generate the ramp.
The phenomenon is called dark tone compression: the perceptual distance between adjacent steps collapses at the dark end of the scale, even when the mathematical distance is uniform.
Why It Happens: Color Space Non-Uniformity
A color ramp is generated by interpolating between a base color and the dark extreme. The interpolation is linear in some color space — but linear in the wrong space produces non-linear perceptual results.
The human visual system is non-linear. We are far more sensitive to differences in dark tones than the numbers suggest, and far less sensitive to differences in bright tones. A color space that doesn't account for this will distribute steps incorrectly — too many in the brights where distinction is easy, too few in the darks where it's hard.
Each interpolation method handles this differently.
HSL and HSB: The Worst Offenders
HSL (Hue, Saturation, Lightness) and HSB (Hue, Saturation, Brightness) are the most common color models in design tools. They are also the most perceptually non-uniform.
In HSL, "lightness" is a mathematical construct that doesn't correspond to perceived brightness. Moving from L=10 to L=20 appears as a very small perceptual step in practice, while the same 10-point move from L=50 to L=60 is a dramatic jump.
When you generate a ramp in HSL — stepping L from 10 to 90 in equal increments — the dark end gets compressed. Steps 1 through 4 look nearly identical. The ramp collapses.
HSB has the same problem with a different formula. Saturation and brightness interact in ways that produce muddy, indistinct darks.
The specific failure: In HSL, as lightness approaches 0, all colors converge to black regardless of hue and saturation. A dark blue and a dark red at L=5 are perceptually indistinguishable. The palette loses its hue identity in the dark zone — and without hue identity, the dark shades have nothing to differentiate them.
Linear RGB: A Different Problem
Interpolating in linear RGB (before gamma correction) is physically accurate — it corresponds to how light actually mixes. But human vision applies its own non-linear response on top of that.
The result: the perceptual midpoint of a ramp in linear RGB is not at the RGB midpoint. It's shifted toward the dark end. A ramp from black to white in linear RGB looks like it jumps quickly from dark to light, then crawls the rest of the way.
Dark steps look too similar. Light steps look too different. The compression is less severe than HSL, but it's still present.
CIELAB and LCH: The Right Idea, Imperfect Execution
CIELAB was designed to be perceptually uniform — equal numerical distances should correspond to equal perceived differences. For its time (1976), it was a significant improvement.
LCH (Lightness, Chroma, Hue) is CIELAB expressed in polar coordinates, making it more intuitive for color work. Interpolating in LCH produces ramps that are far more evenly distributed perceptually — the dark end no longer collapses as dramatically.
The remaining problem: CIELAB and LCH have a known flaw called hue linearity error. Interpolating between two hues in LCH can produce unexpected hue shifts at intermediate steps — blues shift toward purple, greens toward yellow. For a monochromatic ramp, this is less critical, but for brand colors with a specific hue identity, LCH can drift.
Additionally, CIELAB's perceptual uniformity is only approximate. It was calibrated for specific reference conditions and has known failures in blue and purple regions.
OKLCH: Perceptual Uniformity Without Hue Drift
OKLCH is a 2020 refinement of LCH by Björn Ottosson, designed to fix the specific failures of CIELAB. It achieves better perceptual uniformity across all hue regions and significantly reduces the hue linearity error during interpolation.
For color ramp generation, OKLCH has three practical advantages:
1. Even step distribution. Steps generated in OKLCH space are perceptually equidistant from each other. The dark end no longer compresses — shade 1 and shade 2 are as distinguishable as shade 6 and shade 7.
2. Hue stability. Interpolating along a ramp in OKLCH preserves hue identity far better than LCH. A blue brand color stays blue from shade 1 to shade 12, rather than drifting toward purple in the darks or cyan in the lights.
3. Predictable chroma arc. Chroma (saturation) changes smoothly through the ramp without the irregular spikes that appear in HSL-based generation.
OKLCH is now supported natively in CSS (oklch()) and is increasingly the default in modern color tools. Its adoption reflects a broad consensus that it's the most suitable space for systematic color work.
The WCAG Constraint Problem
Even with OKLCH, a ramp that is perceptually uniform may still fail WCAG requirements.
WCAG 4.5:1 is measured in relative luminance — a formula based on linearized RGB values. Perceptual uniformity (how we see differences) and WCAG contrast (how the standard measures differences) are not the same thing.
A ramp built purely for perceptual uniformity can have steps that look distinct to the eye but fail 4.5:1 — because the luminance delta between adjacent steps is too small in the region where WCAG is most demanding (the mid-lightness zone).
This creates a tension:
- Perceptual uniformity requires spreading steps evenly across the perceived range.
- WCAG compliance requires sufficient luminance distance between steps designated as text/background pairs.
These two requirements pull the ramp in different directions. Most tools optimize for one and ignore the other.
Chromametry's Approach: Constrained OKLCH Interpolation
Chromametry generates ramps by interpolating in OKLCH with an additional constraint: the resulting step distribution must satisfy contrast span K across the full scale.
This means the algorithm doesn't just distribute steps evenly — it verifies that the luminance deltas at each position of the ramp are sufficient to guarantee a valid K. If the naive OKLCH interpolation produces a step distribution where K would be too large (meaning WCAG forces too few usable pairs), the chroma curve is adjusted to push luminance deltas into a better configuration while preserving hue stability.
In practice, this produces ramps that:
- Don't compress in the darks. The dark shades are perceptually distinct because OKLCH distributes them correctly.
- Don't compress in the lights. Same reason — the light end retains distinction rather than washing out to near-white.
- Guarantee full WCAG coverage. The contrast span K is as low as mathematically achievable for the step count, meaning the maximum number of shade pairs pass 4.5:1.
- Maintain hue identity. The brand color stays recognizable at both extremes.
No interpolation method can simultaneously maximize perceptual uniformity and minimize contrast span — there are trade-offs at the margins. Chromametry resolves the trade-off by treating WCAG compliance as a hard constraint and maximizing perceptual quality within it, rather than treating them as independent concerns.
What This Means in Practice
If you've ever looked at a generated dark palette and found the shadows muddy and undifferentiated, the issue was almost certainly interpolation in HSL or HSB.
If you've built a palette in LCH and found your blues drifting toward purple at the dark end, the issue was hue linearity error.
If you've found a perceptually beautiful OKLCH palette where your components still fail WCAG, the issue was the missing contrast constraint.
The solution is not to try harder with the same tool. It's to use a generation method that treats perceptual uniformity and WCAG compliance as a joint problem — solved together, not sequentially.
→ Generate a palette → Lightness Linearity metric → Hue Stability metric