Color Palette Generation Building a Full Palette From a Single Hex
Pelajari cara membuat palet warna lengkap, semantik, dan siap mode gelap dari satu kode hex merek menggunakan teori warna HSL dan JavaScript.
You’ve got a brand hex. Maybe it’s from a logo, a style guide, or just a color you like. Now you need a full palette — tints, shades, complementary colors, semantic tokens, dark mode variants. This guide walks through exactly how to build that, programmatically and correctly.
The Color Theory That Actually Matters
Most color theory you’ll encounter in design school doesn’t translate directly to UI work. Here’s what does:
| Tipe Harmoni | How to Generate | Terbaik Untuk | Contoh |
|---|---|---|---|
| Komplementer | Rotate hue 180° | High-contrast accents, CTAs | Blue primary + orange accent |
| Analogous | ±30° hue rotation | Backgrounds, subtle gradients | Blue + teal + indigo |
| Triadik | Three hues at 120° | Colorful dashboards, data viz | Red + yellow + blue |
| Split-complementary | 180° ± 30° | Softer contrast than complementary | Blue + yellow-orange + red-orange |
For most UI libraries, you’ll use your brand color as the primary, an analogous neighbor as secondary, and a complementary or split-complementary hue for accents and interactive states.
Why HSL Beats Hex for Palette Work
Hex and RGB encode color as hardware channels — not as humans perceive color. HSL (Hue, Saturation, Lightness) maps to perception:
- Hue — the color itself (0–360°, where 0 = red, 120 = green, 240 = blue)
- Saturation — how vivid vs. gray (0% = grayscale, 100% = full color)
- Lightness — how light or dark (0% = black, 100% = white)
This matters because to generate a tint of your brand color, you don’t mix it with white — you increase the lightness in HSL. The hue stays exactly the same. That’s not guaranteed when you mix hex values mathematically.
Generating Tints and Shades the Right Way
The wrong way is common: lerp the hex toward #ffffff for tints, toward #000000 for shades. This introduces hue drift and desaturation artifacts — your “light blue” becomes a washed-out gray-blue.
The correct way: parse your hex to HSL, then vary only the lightness:
/**
* Generate a 10-step shade scale from a base HSL color.
* Returns shades from 50 (lightest) to 950 (darkest), like Tailwind.
* @param {number} h - Hue (0–360)
* @param {number} s - Saturation (0–100)
* @param {number} l - Base lightness (0–100)
* @returns {Object} - Scale object: { 50, 100, 200, ..., 900, 950 }
*/
function generateShadeScale(h, s, l) {
// Lightness stops mapped to Tailwind-style scale keys
const stops = [
[50, 95],
[100, 90],
[200, 80],
[300, 70],
[400, 60],
[500, l], // 500 = your base color
[600, 40],
[700, 30],
[800, 20],
[900, 12],
[950, 7],
];
const scale = {};
for (const [key, lightness] of stops) {
scale[key] = `hsl(${h}, ${s}%, ${lightness}%)`;
}
return scale;
}
// Example: brand color #3b82f6 (Tailwind blue-500)
// HSL ≈ hsl(217, 91%, 60%)
const palette = generateShadeScale(217, 91, 60);
// palette[50] → "hsl(217, 91%, 95%)" — near-white blue tint
// palette[500] → "hsl(217, 91%, 60%)" — brand color
// palette[900] → "hsl(217, 91%, 12%)" — near-black blue shade
The key insight: hue and saturation stay constant across the entire scale. Only lightness changes. This produces a visually cohesive scale that reads as the same color family at every weight.
Need to generate this from a hex? Use the free Pengekstrak Palet Warna to extract HSL values from any color instantly.
The 50–950 Design System Scale
Tailwind popularized the 11-stop scale (50, 100–900, 950). It’s now a de facto standard in design systems because it maps cleanly to use cases:
- 50–100: Page backgrounds, hover states on light surfaces
- 200–300: Borders, subtle dividers, disabled states
- 400–500: Interactive elements — buttons, links, focus rings
- 600–700: Hover/active states for interactive elements
- 800–900: Text on light backgrounds
- 950: Near-black for high-contrast headings
When you generate this scale for your brand color, you automatically get every shade you need for any component state — without making per-component color decisions.
From Brand Hex to Full Working Palette
Here’s the practical workflow when you have a single brand hex:
- Parse to HSL. Mengubah
#1d4ed8→hsl(221, 74%, 48%) - Generate the primary scale. Run the shade function above for the full 11-stop scale.
- Derive secondary. Rotate hue ±30° for an analogous secondary:
hsl(251, 74%, 48%)(purple-blue). - Derive accent. Rotate hue 180° for complementary:
hsl(41, 74%, 48%)(amber). - Generate scales for all three. Same shade function, different hue inputs.
You can preview the full result — including harmony types — with the Generator Skema Warna before writing a line of code.
Semantic Color Tokens
Raw scale values are for your palette primitives. Semantic tokens are what your components actually use:
const tokens = {
// Map scale values to semantic names
'color-primary': palette[500], // brand color
'color-primary-hover': palette[600],
'color-primary-subtle': palette[50],
'color-text': palette[900],
'color-text-muted': palette[600],
'color-border': palette[200],
'color-bg': palette[50],
// Status colors — separate scales per semantic group
'color-success': 'hsl(142, 71%, 45%)',
'color-warning': 'hsl(38, 92%, 50%)',
'color-danger': 'hsl(0, 84%, 60%)',
};
This separation is what makes dark mode tractable. Your components reference color-text, bukan palette[900]. In dark mode, you just remap the token — not every component.
Dark Mode: Inverting the Scale
A well-built HSL palette inverts almost automatically. The rule: swap light and dark ends of the scale, then adjust midpoints slightly for perceptual balance.
// Light mode
const lightTokens = {
'color-bg': palette[50], // near-white background
'color-text': palette[900], // near-black text
'color-border': palette[200],
};
// Dark mode — same scale, inverted stops
const darkTokens = {
'color-bg': palette[950], // near-black background
'color-text': palette[50], // near-white text
'color-border': palette[800],
};
Because hue and saturation stay constant across the scale, your brand identity survives the inversion. A blue primary in light mode reads as the same blue in dark mode — just brighter against the dark surface. That’s the compounding benefit of building your palette in HSL from the start.
Putting It Together
Starting from a single hex, you can now generate a complete, semantically-named, dark-mode-ready palette in under 50 lines of JavaScript. The key steps:
- Parse hex → HSL
- Generate an 11-stop lightness scale, holding hue and saturation fixed
- Derive secondary and accent hues via rotation
- Map primitive scale values to semantic tokens
- Remap tokens for dark mode
For quick prototyping without writing the code yourself, the Generator Skema Warna dan Pengekstrak Palet Warna handle all of this visually — export the result as CSS variables or a JSON token file and drop it straight into your design system.
Anda mungkin juga menyukai
Instal Ekstensi Kami
Tambahkan alat IO ke browser favorit Anda untuk akses instan dan pencarian lebih cepat
恵 Papan Skor Telah Tiba!
Papan Skor adalah cara yang menyenangkan untuk melacak permainan Anda, semua data disimpan di browser Anda. Lebih banyak fitur akan segera hadir!
Alat Wajib Coba
Lihat semua Pendatang baru
Lihat semuaMemperbarui: Kita alat terbaru ditambahkan pada 12 Mei 2026
