Start with one brand color, generate lighter and darker variations to create contrast, then check each pair against WCAG standards for accessibility. This creates a reliable, readable palette without guessing or manual trial-and-error.
Why Start with a Single Brand Color?
A cohesive palette begins with one anchor color. This is usually your logo color or primary button hue. Everything else derives from it. Starting with multiple colors often leads to clashes and inconsistent spacing. Pick the hex value that best represents your brand’s personality. For this guide, we use #4F46E5, a vibrant indigo suitable for modern interfaces. This single choice dictates the hue family for the entire system, ensuring visual harmony without complex color theory calculations.
Generating Harmonized Variations
Once you have your base hex, create a scale. A monochromatic scale adjusts lightness and saturation while keeping the hue consistent. This avoids the muddy look that happens when you mix different hues randomly. You need a light background color, a medium body text color, and your primary brand color for accents.
Using #4F46E5 as the base, we generate a scale by adjusting lightness in a perceptual color space like Oklch. This prevents the color from shifting toward blue or purple as it gets lighter.
Here is the resulting monochromatic scale:
:root {
--color-primary-50: #eef2ff;
--color-primary-100: #e0e7ff;
--color-primary-500: #4f46e5;
--color-primary-700: #3730a3;
--color-primary-900: #1e1b4b;
}
The 50 shade is nearly white with a hint of indigo, ideal for backgrounds. The 500 shade is your primary action color. The 900 shade provides deep contrast for headings. Notice how the hue remains consistent across all steps.
Verifying Accessibility with WCAG Standards
Contrast ratios determine if text is readable against backgrounds. WCAG AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text. AAA requires 7:1 and 4.5:1 respectively. You must check every combination in your scale.
Let’s verify #4F46E5 (primary) against #ffffff (white background). The contrast ratio is approximately 4.56:1. This passes AA for normal text. Now check #3730a3 against #ffffff. The ratio is higher, passing AAA easily. Conversely, checking #4F46E5 against #eef2ff yields a ratio of approximately 5.6:1, which meets AA standards for normal body text.
Always test your specific text colors against your specific background colors. Do not assume a light background works with any dark text. Small text needs higher contrast than large headings.
Naming Tokens for Readability
Hex codes are hard to remember. Use semantic names that describe function, not appearance. Instead of blue-dark, use text-primary or bg-subtle. This makes your CSS maintainable. If you change your brand color later, you update one variable, and the name remains accurate.
Use a numeric scale for shades. primary-50 is lighter than primary-500. This hierarchy helps developers choose the right shade without guessing. Avoid names like light-blue or dark-indigo because they become inaccurate if you tweak the saturation slightly. Stick to numbers or functional roles.
Here is how to name your tokens for clarity:
:root {
--color-bg-base: #ffffff;
--color-bg-subtle: #eef2ff;
--color-text-primary: #1e1b4b;
--color-text-secondary: #3730a3;
--color-action-primary: #4f46e5;
}
These names tell the developer exactly where to use each color. bg-base is for main backgrounds. text-primary is for headings and body copy. action-primary is for buttons and links.
Exporting to CSS and Tailwind
Most projects use CSS variables or Tailwind classes. You need a format that integrates easily. CSS variables work in any modern browser. Tailwind config objects work in Tailwind-based projects. Both formats rely on the same underlying hex values.
Here is the CSS variable block ready for your stylesheet:
:root {
--color-primary-50: #eef2ff;
--color-primary-100: #e0e7ff;
--color-primary-500: #4f46e5;
--color-primary-700: #3730a3;
--color-primary-900: #1e1b4b;
}
For Tailwind, you export a JavaScript object. This integrates into your tailwind.config.js file. The structure mirrors the CSS variables but uses object syntax.
module.exports = {
theme: {
extend: {
colors: {
primary: {
50: '#eef2ff',
100: '#e0e7ff',
500: '#4f46e5',
700: '#3730a3',
900: '#1e1b4b',
},
},
},
},
};
Copy the generated palette blocks directly from ColorWell. The tool provides clean, ready-to-use code formatting, eliminating the need for manual adjustments to commas or quotes when moving from design to code.
Common Pitfalls in Palette Creation
Avoid over-complicating your palette. Many designers create ten shades when three suffice. Too many options lead to inconsistency. Stick to a light background, a medium text color, and a primary accent. Add a dark shade for headings if needed. Four to five colors are usually enough for most interfaces.
Do not ignore contrast checks. A beautiful color might fail accessibility standards. Always verify text readability before finalizing. Test your palette on different screens. Some monitors wash out colors, reducing contrast. Check your colors on both light and dark mode settings if your site supports them.
Avoid using pure black (#000000) for text. Pure black can cause eye strain on bright screens. Use a very dark gray or a deep tint of your brand color instead. This creates a softer, more readable experience. For #4F46E5, #1e1b4b is a better choice than black for headings.
Finally, keep your naming convention consistent. If you use numbers for shades, use them everywhere. If you use semantic names, stick to them. Mixing primary-500 with main-blue creates confusion. Choose one style and apply it across all tokens. This clarity pays off when your project grows and multiple developers join the team.