Β· By DevToolHub Team

CSS Color Formats: HEX vs RGB vs HSL vs OKLCH

CSS gives you multiple ways to define colors, from the classic HEX codes to the modern OKLCH. Each format has different strengths β€” understanding them helps you pick the right one for your project, build consistent color systems, and avoid surprises.

HEX β€” The Classic

HEX colors represent red, green, and blue channels as hexadecimal values:

color: #3b82f6;          /* 6-digit: RR GG BB */
color: #3b82f680;        /* 8-digit: RR GG BB AA (with opacity) */
color: #38f;             /* 3-digit shorthand: R G B */

Each pair of hex digits represents a value from 0 (00) to 255 (ff):

ComponentHEXDecimal
Red3b59
Green82130
Bluef6246

When to use HEX:

  • Quick one-off colors
  • Pasting values from Figma, Sketch, or design tools (they default to HEX)
  • When you want compact notation

Drawbacks:

  • Not human-readable β€” #3b82f6 doesn’t tell you the color is blue
  • Hard to create variations (lighter, darker, more muted) by editing values
  • No built-in opacity (though 8-digit HEX adds it)

RGB β€” Red, Green, Blue

RGB defines colors using the additive color model β€” the same model your screen uses:

/* Modern syntax (recommended) */
color: rgb(59 130 246);
color: rgb(59 130 246 / 0.5);     /* with 50% opacity */

/* Legacy syntax (still works) */
color: rgb(59, 130, 246);
color: rgba(59, 130, 246, 0.5);

Each channel is 0–255. You can also use percentages: rgb(23% 51% 96%).

When to use RGB:

  • When working with canvas, WebGL, or image processing (they use RGB natively)
  • When your color values come from an API or computation in RGB
  • When you need programmatic color manipulation

Drawbacks:

  • Not intuitive β€” β€œmake this blue slightly lighter” requires changing multiple values
  • Perceptually non-uniform β€” equal numeric changes don’t look like equal visual changes

HSL β€” Hue, Saturation, Lightness

HSL maps colors to a cylinder, making relationships between colors intuitive:

color: hsl(220 90% 56%);
color: hsl(220 90% 56% / 0.5);   /* with opacity */
ComponentRangeMeaning
H (Hue)0–360Position on the color wheel (0=red, 120=green, 240=blue)
S (Saturation)0–100%Intensity (0%=gray, 100%=vivid)
L (Lightness)0–100%Brightness (0%=black, 50%=pure color, 100%=white)

When to use HSL:

  • Building color palettes and design systems
  • Creating hover/active states (just change lightness)
  • When you need color variations that are easy to reason about
:root {
  --brand: hsl(220 90% 56%);
  --brand-light: hsl(220 90% 70%);    /* lighter: increase L */
  --brand-dark: hsl(220 90% 40%);     /* darker: decrease L */
  --brand-muted: hsl(220 30% 56%);    /* muted: decrease S */
}

Drawbacks:

  • Perceptually non-uniform β€” this is the big one. hsl(60 100% 50%) (yellow) looks far brighter than hsl(240 100% 50%) (blue), even though both have the same lightness value. This makes it hard to create palettes where colors feel equally prominent.

OKLCH β€” The Modern Standard

OKLCH is a perceptually uniform color space introduced in CSS Color Level 4:

color: oklch(0.63 0.18 255);
color: oklch(0.63 0.18 255 / 0.5);   /* with opacity */
ComponentRangeMeaning
L (Lightness)0–1Perceptual brightness (0=black, 1=white)
C (Chroma)0–0.4+Color intensity (0=gray, higher=more vivid)
H (Hue)0–360Color wheel position (similar to HSL)

The key difference from HSL: lightness is perceptually uniform. Changing L by the same amount always looks like the same amount of change, regardless of hue. This makes it possible to create color palettes where all colors feel equally bright.

/* These all look equally bright β€” try this with HSL and they won't */
--red:    oklch(0.65 0.2 25);
--green:  oklch(0.65 0.2 145);
--blue:   oklch(0.65 0.2 255);
--purple: oklch(0.65 0.2 310);

When to use OKLCH:

  • Design systems and color tokens (consistent perceived brightness)
  • Accessible color palettes (predictable contrast ratios)
  • Any project where color consistency across hues matters

Browser support: Chrome 111+, Safari 16.4+, Firefox 113+ (all 2023+). For older browsers, add a fallback:

.button {
  background: #3b82f6;                    /* fallback */
  background: oklch(0.63 0.18 255);       /* modern */
}

Side-by-Side Comparison

HEXRGBHSLOKLCH
ReadabilityLowLowHighHigh
Creating variationsHardHardEasyEasy
Perceptually uniformNoNoNoYes
Opacity support8-digit/ alpha/ alpha/ alpha
Browser supportAllAllAllModern (2023+)
Best forQuick valuesComputationPalettesDesign systems

Named Colors

CSS also supports 148 named colors: red, cornflowerblue, rebeccapurple, etc. They’re great for prototyping and readable code, but limited for production use since you can’t adjust them.

color: cornflowerblue;         /* #6495ED / hsl(219 79% 66%) */
color: rebeccapurple;          /* #663399 β€” added as a tribute to Eric Meyer's daughter */

Practical Tips

Use CSS custom properties for your palette. Define colors once, reference everywhere:

:root {
  --color-primary: oklch(0.63 0.18 255);
  --color-primary-hover: oklch(0.56 0.18 255);   /* darker */
  --color-primary-light: oklch(0.90 0.05 255);   /* light bg */
}

Use currentColor for derived values. It inherits the text color, reducing repetition:

.icon {
  fill: currentColor;
  border: 1px solid currentColor;
}

Test contrast ratios. WCAG 2.1 requires 4.5:1 contrast for normal text and 3:1 for large text. Use tools like our Color Converter to check values and convert between formats.

Try It Yourself

Use our Color Converter to convert between HEX, RGB, and HSL formats instantly β€” with a visual color picker and CSS-ready output values.

Further Reading

FAQ

Which CSS color format should I use?
For most projects, HSL is the best default β€” it's intuitive and easy to create variations. Use HEX for quick one-off colors and when pasting from design tools. Use OKLCH if you need perceptually uniform colors (color systems, design tokens) and your browser support requirements allow it. RGB is rarely the best choice for hand-written CSS.
What is OKLCH and why should I care?
OKLCH is a perceptually uniform color space β€” meaning that changing the lightness value by 10% looks like the same amount of change regardless of the hue. In HSL, lightness is mathematically defined but perceptually inconsistent (yellow at 50% looks much brighter than blue at 50%). OKLCH fixes this, making it ideal for design systems and accessible color palettes.
Can I use OKLCH in production today?
Yes, with a fallback. OKLCH is supported in Chrome 111+, Safari 16.4+, and Firefox 113+ (all released in 2023). For older browsers, provide a fallback: color: #3b82f6; color: oklch(0.63 0.18 255);. The second declaration overrides the first in supporting browsers.
What's the difference between opacity in rgba() and the / syntax?
They're functionally identical. rgba(59, 130, 246, 0.5) and rgb(59 130 246 / 0.5) produce the same color. The modern syntax (with /) works in all color functions: hsl(220 90% 56% / 0.5), oklch(0.63 0.18 255 / 0.5). The rgba() and hsla() functions are now considered legacy syntax.
Why do some colors look different in HEX vs HSL even with the same values?
HEX and HSL use different color models, so there's no direct mapping between raw numbers. #ff0000 in HEX is hsl(0, 100%, 50%) β€” the values look completely different but represent the same red. Use a color converter to translate between formats accurately.
css color design frontend web

Related Tools

Related Articles