OKLCH Studio · Accessible palettes · Data visualisation
Accessible diverging colour scale: orange to blue in nine steps
Updated 2026-10-19
A diverging scale is for values that have a meaningful middle: change from last year, variance from budget, agreement on a survey from disagree to agree. Two hues leave a neutral centre in opposite directions, and the further a value is from the centre, the stronger the colour.
The common red-to-green version fails for red-green colour blindness at the very moment the distinction matters most. This scale uses orange and blue, which stay apart for protanopia and deuteranopia because blue-yellow differences survive. The nine steps are checked under all three simulations, and the centre step is a neutral that is itself 3:1 against the chart background.
Lightness falls away from the centre on the light theme and rises on the dark theme, and the tests check that each side moves monotonically. Use a legend with the centre value labelled, and do not treat colour as the only signal: put the number or a sign in the cell where you can.
How to build a palette like this by hand is explained in the accessible colour palette guide; this page is the finished, verified result.
The palette: light and dark
Hex values are the sRGB result after gamut mapping. The oklch() values are those of the final hex, so converting either gives the same colour.
Light chart: steps, with contrast on the chart background
- 1. #6E080012.04:1
- 2. #7E33008.66:1
- 3. #8C52316.07:1
- 4. #96705C4.28:1
- 5. #94918B3.05:1
- 6. #657C994.17:1
- 7. #4065925.85:1
- 8. #1A4D898.28:1
- 9. #00347D11.43:1
Light theme
- Chart background
#FEFCF4
oklch(0.990 0.011 95.2)
Sample text
- Chart text
#211F19
oklch(0.239 0.011 91.7)
Sample text
- Axis labels
#5B584F
oklch(0.460 0.015 91.7)
Sample text
- Axis line
#8A867C
oklch(0.621 0.015 88.7)
Sample text
- Gridline
#D4D0C5
oklch(0.858 0.016 90.3)
Sample text
- Step 1
#6E0800
oklch(0.343 0.134 30.8)
Sample text
- Step 2
#7E3300
oklch(0.420 0.117 46.4)
Sample text
- Step 3
#8C5231
oklch(0.499 0.091 49.2)
Sample text
- Step 4
#96705C
oklch(0.578 0.057 48.9)
Sample text
- Step 5
#94918B
oklch(0.657 0.009 84.6)
Sample text
- Step 6
#657C99
oklch(0.579 0.052 254.4)
Sample text
- Step 7
#406592
oklch(0.499 0.084 254.1)
Sample text
- Step 8
#1A4D89
oklch(0.420 0.113 254.9)
Sample text
- Step 9
#00347D
oklch(0.346 0.134 259.0)
Sample text
Dark chart: steps, with contrast on the chart background
- 1. #FFBF7F11.20:1
- 2. #FDA6759.37:1
- 3. #CD8E6B6.60:1
- 4. #9D77634.52:1
- 5. #66645D3.05:1
- 6. #6C83A14.64:1
- 7. #7BA2D36.84:1
- 8. #8CC1FF9.62:1
- 9. #9DE2FF12.70:1
Dark theme
- Chart background
#181611
oklch(0.201 0.010 88.8)
Sample text
- Chart text
#EEEBE2
oklch(0.940 0.012 91.5)
Sample text
- Axis labels
#B5B1A7
oklch(0.761 0.015 88.7)
Sample text
- Axis line
#78746B
oklch(0.560 0.014 86.9)
Sample text
- Gridline
#3A362E
oklch(0.334 0.015 84.6)
Sample text
- Step 1
#FFBF7F
oklch(0.850 0.109 65.5)
Sample text
- Step 2
#FDA675
oklch(0.801 0.122 49.7)
Sample text
- Step 3
#CD8E6B
oklch(0.701 0.091 49.8)
Sample text
- Step 4
#9D7763
oklch(0.601 0.056 49.0)
Sample text
- Step 5
#66645D
oklch(0.503 0.011 93.7)
Sample text
- Step 6
#6C83A1
oklch(0.603 0.053 255.2)
Sample text
- Step 7
#7BA2D3
oklch(0.702 0.084 254.5)
Sample text
- Step 8
#8CC1FF
oklch(0.798 0.105 252.9)
Sample text
- Step 9
#9DE2FF
oklch(0.877 0.080 226.1)
Sample text
Contrast table: every verified pair
Pass or fail uses the raw WCAG 2.x ratio; the ratio shown is floored to two decimals so a near miss is never rounded up. APCA Lc is signed: positive is dark on light, negative is light on dark. Each row opens the pair in the checker.
| Pair | WCAG ratio | Target | Normal AA / AAA | Large AA / AAA | APCA Lc | APCA tier | Check |
|---|---|---|---|---|---|---|---|
| Chart text on background#211f19 on #fefcf4 | 16.03:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | +101.6 | Lc 75: body text | Open in checker |
| Axis labels on background#5b584f on #fefcf4 | 6.92:1 | AA 4.5:1 | Pass / Fail | Pass / Pass | +82.8 | Lc 75: body text | Open in checker |
| Axis line on background#8a867c on #fefcf4 | 3.53:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | +62.1 | Lc 60: larger content text | Open in checker |
| Step 1 on background#6e0800 on #fefcf4 | 12.04:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | +94.4 | Lc 75: body text | Open in checker |
| Step 2 on background#7e3300 on #fefcf4 | 8.66:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | +87.8 | Lc 75: body text | Open in checker |
| Step 3 on background#8c5231 on #fefcf4 | 6.07:1 | 3:1 (WCAG 1.4.11) | Pass / Fail | Pass / Pass | +78.9 | Lc 75: body text | Open in checker |
| Step 4 on background#96705c on #fefcf4 | 4.28:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | +68.6 | Lc 60: larger content text | Open in checker |
| Step 5 on background#94918b on #fefcf4 | 3.05:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | +56.6 | Lc 45: headlines and large text | Open in checker |
| Step 6 on background#657c99 on #fefcf4 | 4.17:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | +67.8 | Lc 60: larger content text | Open in checker |
| Step 7 on background#406592 on #fefcf4 | 5.85:1 | 3:1 (WCAG 1.4.11) | Pass / Fail | Pass / Pass | +78.0 | Lc 75: body text | Open in checker |
| Step 8 on background#1a4d89 on #fefcf4 | 8.28:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | +87.0 | Lc 75: body text | Open in checker |
| Step 9 on background#00347d on #fefcf4 | 11.43:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | +94.3 | Lc 75: body text | Open in checker |
| Pair | WCAG ratio | Target | Normal AA / AAA | Large AA / AAA | APCA Lc | APCA tier | Check |
|---|---|---|---|---|---|---|---|
| Chart text on background#eeebe2 on #181611 | 15.16:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −93.9 | Lc 75: body text | Open in checker |
| Axis labels on background#b5b1a7 on #181611 | 8.44:1 | AA 4.5:1 | Pass / Pass | Pass / Pass | −59.3 | Lc 45: headlines and large text | Open in checker |
| Axis line on background#78746b on #181611 | 3.88:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | −28.4 | Below Lc 30 | Open in checker |
| Step 1 on background#ffbf7f on #181611 | 11.20:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | −74.6 | Lc 60: larger content text | Open in checker |
| Step 2 on background#fda675 on #181611 | 9.37:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | −64.8 | Lc 60: larger content text | Open in checker |
| Step 3 on background#cd8e6b on #181611 | 6.60:1 | 3:1 (WCAG 1.4.11) | Pass / Fail | Pass / Pass | −48.1 | Lc 45: headlines and large text | Open in checker |
| Step 4 on background#9d7763 on #181611 | 4.52:1 | 3:1 (WCAG 1.4.11) | Pass / Fail | Pass / Pass | −33.5 | Lc 30: non-text and incidental | Open in checker |
| Step 5 on background#66645d on #181611 | 3.05:1 | 3:1 (WCAG 1.4.11) | Fail / Fail | Pass / Fail | −21.2 | Below Lc 30 | Open in checker |
| Step 6 on background#6c83a1 on #181611 | 4.64:1 | 3:1 (WCAG 1.4.11) | Pass / Fail | Pass / Pass | −34.4 | Lc 30: non-text and incidental | Open in checker |
| Step 7 on background#7ba2d3 on #181611 | 6.84:1 | 3:1 (WCAG 1.4.11) | Pass / Fail | Pass / Pass | −49.6 | Lc 45: headlines and large text | Open in checker |
| Step 8 on background#8cc1ff on #181611 | 9.62:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | −66.1 | Lc 60: larger content text | Open in checker |
| Step 9 on background#9de2ff on #181611 | 12.70:1 | 3:1 (WCAG 1.4.11) | Pass / Pass | Pass / Pass | −82.2 | Lc 75: body text | Open in checker |
Colour-blind check
Colours are simulated with the Machado et al. (2009) model at full severity (culori). The figure is the smallest ΔE-OK ×100, the Euclidean distance in OKLab, between any two colours. The build fails if it drops below 5. Still pair colour with labels or patterns (WCAG 1.4.1).
| Vision | Simulated colours | Min ΔE-OK ×100 | Closest pair |
|---|---|---|---|
| Normal vision | 7.8 (≥ 5) | 8 and 9 | |
| Protanopia | 8.1 (≥ 5) | 8 and 9 | |
| Deuteranopia | 8.1 (≥ 5) | 8 and 9 | |
| Tritanopia | 6.1 (≥ 5) | 1 and 2 |
| Vision | Simulated colours | Min ΔE-OK ×100 | Closest pair |
|---|---|---|---|
| Normal vision | 5.9 (≥ 5) | 1 and 2 | |
| Protanopia | 6.9 (≥ 5) | 1 and 2 | |
| Deuteranopia | 5.7 (≥ 5) | 1 and 2 | |
| Tritanopia | 5.7 (≥ 5) | 1 and 2 |
Why these colours
Orange sits at OKLCH hue 50 and blue at hue 255, close to opposite on the wheel. The centre is a warm neutral at hue 90 with chroma 0.01, the lightest tone that still reaches 3:1 on the background. Lightness steps are equal on each side, and chroma grows toward the ends along a gentle curve, limited by what sRGB can hold.
Equal lightness steps give a symmetric scale: a value of plus 2 and minus 2 are equally strong. The smallest difference between any two colours, including mirrored pairs on opposite sides, is measured under each simulation and must reach 5. Tritanopia is the weakest case for orange and blue, and the table shows how it fares.
The generator solved 24 pairs (12 light, 12 dark), and all of them meet their target on the raw WCAG ratio. The tightest is step 5 on background in the dark theme at 3.05:1 against a target of 3:1.
How to use it
- Centre the scale on a value that means something, such as zero, target or neutral, and say so on the legend.
- Do not use this for a quantity without a midpoint; use the sequential scale instead.
- Label strong values with numbers, and consider a different shape for positive and negative.
- Keep orange as the lower or negative side consistently across charts so readers learn the direction.
- Avoid pairing it on the same page with red-green status colours; the meanings will compete.
Chart advice
- Mark the midpoint on the legend with a tick and its value.
- Use a binned scale, not a continuous one, so values are comparable with the legend.
- Annotate extremes directly on the chart.
Export
Generated from the verified values above, never typed by hand. Light and dark are both included.
CSS custom properties (hex, then oklch())
/* sRGB hex first: every browser. */
:root {
--color-background: #fefcf4;
--color-text: #211f19;
--color-text-muted: #5b584f;
--color-axis: #8a867c;
--color-gridline: #d4d0c5;
--color-step-1: #6e0800;
--color-step-2: #7e3300;
--color-step-3: #8c5231;
--color-step-4: #96705c;
--color-step-5: #94918b;
--color-step-6: #657c99;
--color-step-7: #406592;
--color-step-8: #1a4d89;
--color-step-9: #00347d;
}
.dark {
--color-background: #181611;
--color-text: #eeebe2;
--color-text-muted: #b5b1a7;
--color-axis: #78746b;
--color-gridline: #3a362e;
--color-step-1: #ffbf7f;
--color-step-2: #fda675;
--color-step-3: #cd8e6b;
--color-step-4: #9d7763;
--color-step-5: #66645d;
--color-step-6: #6c83a1;
--color-step-7: #7ba2d3;
--color-step-8: #8cc1ff;
--color-step-9: #9de2ff;
}
/* oklch() where supported: the same colours, unclipped values of the hex above. */
@supports (color: oklch(0 0 0)) {
:root {
--color-background: oklch(0.990 0.011 95.2);
--color-text: oklch(0.239 0.011 91.7);
--color-text-muted: oklch(0.460 0.015 91.7);
--color-axis: oklch(0.621 0.015 88.7);
--color-gridline: oklch(0.858 0.016 90.3);
--color-step-1: oklch(0.343 0.134 30.8);
--color-step-2: oklch(0.420 0.117 46.4);
--color-step-3: oklch(0.499 0.091 49.2);
--color-step-4: oklch(0.578 0.057 48.9);
--color-step-5: oklch(0.657 0.009 84.6);
--color-step-6: oklch(0.579 0.052 254.4);
--color-step-7: oklch(0.499 0.084 254.1);
--color-step-8: oklch(0.420 0.113 254.9);
--color-step-9: oklch(0.346 0.134 259.0);
}
.dark {
--color-background: oklch(0.201 0.010 88.8);
--color-text: oklch(0.940 0.012 91.5);
--color-text-muted: oklch(0.761 0.015 88.7);
--color-axis: oklch(0.560 0.014 86.9);
--color-gridline: oklch(0.334 0.015 84.6);
--color-step-1: oklch(0.850 0.109 65.5);
--color-step-2: oklch(0.801 0.122 49.7);
--color-step-3: oklch(0.701 0.091 49.8);
--color-step-4: oklch(0.601 0.056 49.0);
--color-step-5: oklch(0.503 0.011 93.7);
--color-step-6: oklch(0.603 0.053 255.2);
--color-step-7: oklch(0.702 0.084 254.5);
--color-step-8: oklch(0.798 0.105 252.9);
--color-step-9: oklch(0.877 0.080 226.1);
}
}Tailwind CSS v4 @theme
@theme {
/* light */
--color-background: oklch(0.990 0.011 95.2); /* #fefcf4 */
--color-text: oklch(0.239 0.011 91.7); /* #211f19 */
--color-text-muted: oklch(0.460 0.015 91.7); /* #5b584f */
--color-axis: oklch(0.621 0.015 88.7); /* #8a867c */
--color-gridline: oklch(0.858 0.016 90.3); /* #d4d0c5 */
--color-step-1: oklch(0.343 0.134 30.8); /* #6e0800 */
--color-step-2: oklch(0.420 0.117 46.4); /* #7e3300 */
--color-step-3: oklch(0.499 0.091 49.2); /* #8c5231 */
--color-step-4: oklch(0.578 0.057 48.9); /* #96705c */
--color-step-5: oklch(0.657 0.009 84.6); /* #94918b */
--color-step-6: oklch(0.579 0.052 254.4); /* #657c99 */
--color-step-7: oklch(0.499 0.084 254.1); /* #406592 */
--color-step-8: oklch(0.420 0.113 254.9); /* #1a4d89 */
--color-step-9: oklch(0.346 0.134 259.0); /* #00347d */
/* dark: use as dark:bg-background-dark, or remap under a .dark selector */
--color-background-dark: oklch(0.201 0.010 88.8); /* #181611 */
--color-text-dark: oklch(0.940 0.012 91.5); /* #eeebe2 */
--color-text-muted-dark: oklch(0.761 0.015 88.7); /* #b5b1a7 */
--color-axis-dark: oklch(0.560 0.014 86.9); /* #78746b */
--color-gridline-dark: oklch(0.334 0.015 84.6); /* #3a362e */
--color-step-1-dark: oklch(0.850 0.109 65.5); /* #ffbf7f */
--color-step-2-dark: oklch(0.801 0.122 49.7); /* #fda675 */
--color-step-3-dark: oklch(0.701 0.091 49.8); /* #cd8e6b */
--color-step-4-dark: oklch(0.601 0.056 49.0); /* #9d7763 */
--color-step-5-dark: oklch(0.503 0.011 93.7); /* #66645d */
--color-step-6-dark: oklch(0.603 0.053 255.2); /* #6c83a1 */
--color-step-7-dark: oklch(0.702 0.084 254.5); /* #7ba2d3 */
--color-step-8-dark: oklch(0.798 0.105 252.9); /* #8cc1ff */
--color-step-9-dark: oklch(0.877 0.080 226.1); /* #9de2ff */
}shadcn/ui variables (:root and .dark)
:root {
--background: oklch(0.990 0.011 95.2);
--foreground: oklch(0.239 0.011 91.7);
--muted-foreground: oklch(0.460 0.015 91.7);
--border: oklch(0.858 0.016 90.3);
--input: oklch(0.621 0.015 88.7);
--chart-1: oklch(0.343 0.134 30.8);
--chart-2: oklch(0.499 0.091 49.2);
--chart-3: oklch(0.657 0.009 84.6);
--chart-4: oklch(0.499 0.084 254.1);
--chart-5: oklch(0.346 0.134 259.0);
}
.dark {
--background: oklch(0.201 0.010 88.8);
--foreground: oklch(0.940 0.012 91.5);
--muted-foreground: oklch(0.761 0.015 88.7);
--border: oklch(0.334 0.015 84.6);
--input: oklch(0.560 0.014 86.9);
--chart-1: oklch(0.850 0.109 65.5);
--chart-2: oklch(0.701 0.091 49.8);
--chart-3: oklch(0.503 0.011 93.7);
--chart-4: oklch(0.702 0.084 254.5);
--chart-5: oklch(0.877 0.080 226.1);
}Design tokens (DTCG-style JSON)
{
"color": {
"light": {
"background": {
"$type": "color",
"$value": "oklch(0.990 0.011 95.2)",
"$description": "sRGB #fefcf4"
},
"text": {
"$type": "color",
"$value": "oklch(0.239 0.011 91.7)",
"$description": "sRGB #211f19"
},
"text-muted": {
"$type": "color",
"$value": "oklch(0.460 0.015 91.7)",
"$description": "sRGB #5b584f"
},
"axis": {
"$type": "color",
"$value": "oklch(0.621 0.015 88.7)",
"$description": "sRGB #8a867c"
},
"gridline": {
"$type": "color",
"$value": "oklch(0.858 0.016 90.3)",
"$description": "sRGB #d4d0c5"
},
"step-1": {
"$type": "color",
"$value": "oklch(0.343 0.134 30.8)",
"$description": "sRGB #6e0800"
},
"step-2": {
"$type": "color",
"$value": "oklch(0.420 0.117 46.4)",
"$description": "sRGB #7e3300"
},
"step-3": {
"$type": "color",
"$value": "oklch(0.499 0.091 49.2)",
"$description": "sRGB #8c5231"
},
"step-4": {
"$type": "color",
"$value": "oklch(0.578 0.057 48.9)",
"$description": "sRGB #96705c"
},
"step-5": {
"$type": "color",
"$value": "oklch(0.657 0.009 84.6)",
"$description": "sRGB #94918b"
},
"step-6": {
"$type": "color",
"$value": "oklch(0.579 0.052 254.4)",
"$description": "sRGB #657c99"
},
"step-7": {
"$type": "color",
"$value": "oklch(0.499 0.084 254.1)",
"$description": "sRGB #406592"
},
"step-8": {
"$type": "color",
"$value": "oklch(0.420 0.113 254.9)",
"$description": "sRGB #1a4d89"
},
"step-9": {
"$type": "color",
"$value": "oklch(0.346 0.134 259.0)",
"$description": "sRGB #00347d"
}
},
"dark": {
"background": {
"$type": "color",
"$value": "oklch(0.201 0.010 88.8)",
"$description": "sRGB #181611"
},
"text": {
"$type": "color",
"$value": "oklch(0.940 0.012 91.5)",
"$description": "sRGB #eeebe2"
},
"text-muted": {
"$type": "color",
"$value": "oklch(0.761 0.015 88.7)",
"$description": "sRGB #b5b1a7"
},
"axis": {
"$type": "color",
"$value": "oklch(0.560 0.014 86.9)",
"$description": "sRGB #78746b"
},
"gridline": {
"$type": "color",
"$value": "oklch(0.334 0.015 84.6)",
"$description": "sRGB #3a362e"
},
"step-1": {
"$type": "color",
"$value": "oklch(0.850 0.109 65.5)",
"$description": "sRGB #ffbf7f"
},
"step-2": {
"$type": "color",
"$value": "oklch(0.801 0.122 49.7)",
"$description": "sRGB #fda675"
},
"step-3": {
"$type": "color",
"$value": "oklch(0.701 0.091 49.8)",
"$description": "sRGB #cd8e6b"
},
"step-4": {
"$type": "color",
"$value": "oklch(0.601 0.056 49.0)",
"$description": "sRGB #9d7763"
},
"step-5": {
"$type": "color",
"$value": "oklch(0.503 0.011 93.7)",
"$description": "sRGB #66645d"
},
"step-6": {
"$type": "color",
"$value": "oklch(0.603 0.053 255.2)",
"$description": "sRGB #6c83a1"
},
"step-7": {
"$type": "color",
"$value": "oklch(0.702 0.084 254.5)",
"$description": "sRGB #7ba2d3"
},
"step-8": {
"$type": "color",
"$value": "oklch(0.798 0.105 252.9)",
"$description": "sRGB #8cc1ff"
},
"step-9": {
"$type": "color",
"$value": "oklch(0.877 0.080 226.1)",
"$description": "sRGB #9de2ff"
}
}
}
}Open in the studio
Take the first series colour into the picker, build a tonal scale from it, or check any pair of your own.
Open #6E0800 in the OKLCH picker →Build a tonal scale →Check a pair
FAQ
- Why not red and green?
- They are the hues most often confused in red-green deficiency. Orange and blue differ on the blue-yellow axis, which stays visible for those viewers.
- Does the middle step vanish into the background?
- No. It is a neutral selected to be at least 3:1 against the chart background, so a zero value is visible, not blank.
- How do I show no data?
- Use a hatch pattern or an outline with no fill. A fill colour from the scale would imply a value.
- Can I reduce it to five steps?
- Yes. Take steps 1, 3, 5, 7 and 9, which keeps the symmetry and the neutral centre.