One brand colour is never enough. You need a lighter version for backgrounds, a darker one for text, and several in between for borders and hover states. Picking those by eye produces a palette that feels inconsistent; generating them from one colour does not.
Why shades are numbered
The 50-to-950 convention, popularised by Tailwind CSS, names each step by lightness: 50 is nearly white, 500 sits around the base colour, 950 is nearly black. Numbering rather than naming makes a palette usable — border-slate-200 communicates intent, while light-grey-2 does not.
It also makes palettes swappable. If every colour family exposes the same steps, changing the accent colour across a product becomes a find-and-replace rather than a redesign.
Keeping a ramp even
Stepping lightness in equal numeric increments does not produce an even-looking ramp, because perceived lightness is not linear. The middle steps look bunched while the ends look far apart.
Saturation needs attention too. Holding it constant makes the lightest and darkest steps look garish, so easing it off toward the extremes keeps the ends feeling like neutrals rather than neon. This is the main reason a generated ramp usually looks better than a hand-picked one.
Contrast is a requirement, not a preference
WCAG asks for a contrast ratio of at least 4.5:1 for normal body text and 3:1 for large text, with 7:1 as the stricter AAA target. These are the figures accessibility audits check against.
In practice this decides which steps can carry text. Light steps take dark text, dark steps take light text, and the middle of a ramp is usually where legibility quietly fails — which is exactly where brand colours tend to sit. Check the ratio rather than trusting the look.
In short
Generate the ramp from one colour, ease saturation at the extremes, and check contrast on every step you intend to put text on.
Color Shades Generator
Turn one color into a full 50-950 shade scale, with contrast checks and ready-to-paste CSS, Tailwind or JSON.
Keep reading
Why your link preview isn't showing, and how to fix it
A shared link with no card is nearly always one of five things. How previews are fetched, which tags matter, and why Slack works when WhatsApp won't.
How to read a regular expression without panicking
Regex looks like line noise until you know the four things it is made of. A practical guide to reading any pattern, plus the mistakes that waste the most time.
How to read messy JSON, and fix the errors it throws
Deeply nested API responses are hard to hold in your head. How to navigate JSON structurally, and what the three most common parse errors actually mean.