Prescosoft

Color Tools · CSS Reference

CSS Color Formats Explained: HEX vs RGB vs HSL and When to Use Each

By Prescosoft · 14 min read

Why CSS Has Multiple Color Formats

CSS supports multiple color formats because different formats serve different needs: HEX is compact and widely supported, RGB matches how screens emit light, and HSL is intuitive for human designers adjusting colors by hand.

Each format maps to a different mental model. When a device renders a pixel, it sends red, green, and blue signals — RGB mirrors that hardware reality. But when a designer asks "make this blue a little lighter," they're thinking in terms of lightness and hue, not in raw channel values. HSL captures that intent directly.

HEX sits between these worlds: it's just a compact encoding of RGB values in hexadecimal notation. It's terse, copy-pasteable, and the default output of every design tool from Figma to Photoshop. But it lacks semantic meaning — #7DD3FC tells a machine exactly what to render but tells a human almost nothing about the color until they decode it.

Modern CSS has added even more formats — OKLCH, OKLAB, LCH, and the color() function — to address perceptual uniformity and wide-gamut displays. The result: a specification with over a dozen valid ways to write "blue," each optimized for a different workflow.

HEX Colors Explained

HEX (hexadecimal) notation encodes RGB values as base-16 pairs prefixed with a hash symbol. Each pair represents a channel value from 00 (0 in decimal) to FF (255 in decimal).

Syntax Forms

HEX colors come in four syntactic variants:

  • 6-digit (#RRGGBB): The standard form. #3B82F6 = Red 59, Green 130, Blue 246.
  • 3-digit (#RGB): Shorthand where each digit is doubled. #F00 = #FF0000.
  • 8-digit (#RRGGBBAA): Adds an alpha channel. #3B82F680 = blue at ~50% opacity.
  • 4-digit (#RGBA): Shorthand with alpha. #F008 = #FF000088.

When to Use HEX

  • Quick prototyping: Fast to type, universally understood by design tools.
  • Design tool exports: Figma, Sketch, and Adobe XD all output HEX by default.
  • Legacy CSS: HEX has been supported since CSS1 (1996).
  • Configuration files: Tailwind configs, theme objects, and JSON design tokens typically store colors as HEX strings.

Limitations

  • Hard to mentally parse — #C084FC doesn't immediately tell you what color it is.
  • No alpha in 6-digit form (you need 8-digit, which many designers don't realize exists).
  • No way to manipulate lightness or saturation intuitively — you must convert to another model first.
  • Cannot be animated smoothly in CSS transitions without @property registration.

/* Common HEX values */

.black { color: #000000; } /* or #000 */

.white { color: #FFFFFF; } /* or #FFF */

.blue-500 { color: #3B82F6; }

.semi-white { color: #FFFFFF80; } /* 50% white with alpha */

RGB and RGBA Colors Explained

The RGB model defines colors as additive combinations of red, green, and blue light — exactly how your monitor generates every pixel. Each channel ranges from 0 to 255 in the sRGB gamut.

Legacy Syntax (Comma-Separated)

/* Classic syntax — still fully valid */

.blue { color: rgb(59, 130, 246); }

.overlay { background: rgba(0, 0, 0, 0.5); } /* semi-transparent black */

.highlight { color: rgba(255, 200, 0, 0.8); }

Modern CSS Color Level 4 Syntax

CSS Color Level 4 unified the syntax: no more separate rgba() function. Alpha is expressed with a slash separator, and commas are optional:

/* Modern space-separated syntax with slash for alpha */

.blue { color: rgb(59 130 246); }

.overlay { background: rgb(0 0 0 / 0.5); }

.brand { color: rgb(59 130 246 / 75%); } /* percentage alpha */

When to Use RGB

  • Dynamic manipulation: When JavaScript needs to increment channels (e.g., cycling hues, adjusting brightness on scroll).
  • API responses: Many APIs return colors as { r: 59, g: 130, b: 246 } objects.
  • Exact color matching: When porting colors from device color profiles or calibrated displays.
  • Canvas/WebGL: The ctx.fillStyle in Canvas2D and WebGL uniforms both natively use 0-255 channel values.

HSL Colors Explained

HSL maps colors to three axes that humans actually think in: Hue (what color is it?), Saturation (how vivid?), and Lightness (how bright or dark?). This makes HSL the most intuitive format for manual color adjustment.

The HSL Axes

  • Hue (0–360°): A position on the color wheel. 0° = red, 120° = green, 240° = blue.
  • Saturation (0–100%): 0% is gray, 100% is fully vivid.
  • Lightness (0–100%): 0% is black, 50% is the "pure" color, 100% is white.

/* Legacy comma syntax */

.blue { color: hsl(217, 91%, 60%); }

.blue-with-alpha { color: hsla(217, 91%, 60%, 0.5); }

/* Modern CSS4 syntax */

.blue { color: hsl(217 91% 60%); }

.blue-50 { color: hsl(217 91% 60% / 0.5); }

Why Designers Prefer HSL

Want a darker blue? Lower the L value. Want a muted, pastel version? Drop the saturation. Want to shift from blue to purple? Increase the hue from 240° to 270°. Each adjustment requires changing exactly one number — something impossible in HEX or RGB without mental conversion.

/* HSL palette generation — same hue, varying lightness */

:root {

--blue-50: hsl(217 91% 95%); /* near-white */

--blue-100: hsl(217 91% 90%); /* very light */

--blue-300: hsl(217 91% 75%); /* light */

--blue-500: hsl(217 91% 60%); /* base */

--blue-700: hsl(217 91% 42%); /* dark */

--blue-900: hsl(217 91% 25%); /* very dark */

}

This pattern is the foundation of most component library color systems. Adjust one variable (lightness) and the entire palette stays harmonically consistent. For accessibility guidance on choosing HSL values that meet WCAG contrast ratios, see our WCAG Color Accessibility Guide.

Modern CSS Color Formats: OKLCH, OKLAB, and LCH

Why New Formats Exist

HEX, RGB, and HSL all operate within the sRGB gamut — the color space defined for CRT monitors in 1996. Modern displays (Apple's P3, HDR screens) can reproduce far more vivid colors that sRGB physically cannot express. Additionally, HSL has a perceptual flaw: hsl(60, 100%, 50%) (yellow) appears significantly brighter than hsl(240, 100%, 50%) (blue) even though both have 50% lightness. New formats fix this.

The CSS Color Level 4 specification introduced OKLCH, OKLAB, LCH, and LAB to provide perceptually uniform color spaces where a given numerical change produces a visually equal change regardless of hue. These formats also access the full P3 gamut.

OKLCH (Ok Lightness Chroma Hue)

OKLCH is currently the best perceptual color format for CSS. It combines perceptual uniformity (from the Oklab color space) with the intuitive cylindrical structure designers expect: lightness, chroma (vividness), and hue angle.

/* OKLCH syntax: oklch(L C H) */

.teal { color: oklch(70% 0.15 180); } /* L=70%, Chroma=0.15, Hue=180° */

.vivid-blue { color: oklch(65% 0.25 250); }

.muted-rose { color: oklch(75% 0.1 20); }

/* With alpha */

.overlay { background: oklch(50% 0.2 260 / 0.6); }

The key advantage: changing only the L value always produces a lighter or darker version that looks proportionally lighter — no unwanted hue shifts or perceptual jumps. This makes OKLCH ideal for generating accessible color palettes programmatically.

Color() Function and Display-P3

The color() function lets you specify colors in any registered color space, including Display-P3 for wide-gamut monitors:

/* Display-P3 — more vivid than sRGB allows */

.vivid-green { color: color(display-p3 0 1 0); }

.p3-orange { color: color(display-p3 1 0.5 0 / 0.9); }

/* Fallback pattern */

.hero-gradient {

background: rgb(0 200 80); /* sRGB fallback */

background: color(display-p3 0 0.8 0.3); /* P3 enhancement */

}

Browser support: OKLCH is supported in Chrome 111+, Firefox 113+, Safari 15.4+. The color(display-p3) function has equivalent support. Use @supports or progressive enhancement (declare fallback first) for older browsers.

Comparison Table: Which Format to Use When

Format Syntax Example Alpha Readable Best Use Case Support
HEX #3B82F6 8-digit only Low Static styles, design tokens All browsers
RGB/RGBA rgb(59 130 246) Yes (/ alpha) Medium JS manipulation, Canvas All browsers
HSL hsl(217 91% 60%) Yes (/ alpha) High Palette design, theming All browsers
HWB hwb(217 20% 4%) Yes (/ alpha) Medium Tinting/shading Chrome 101+
OKLCH oklch(70% 0.15 250) Yes (/ alpha) High Perceptual palettes, accessibility Chrome 111+
Color() color(display-p3 0 1 0) Yes (/ alpha) Low Wide-gamut P3 displays Chrome 111+

Converting Between Color Formats

HEX to RGB Conversion (Step-by-Step)

Converting HEX to RGB is straightforward hexadecimal-to-decimal parsing. Let's convert #7DD3FC:

  1. Split into channel pairs: 7D, D3, FC
  2. Convert each hex pair to decimal:
    • 7D = (7 × 16) + 13 = 112 + 13 = 125 (Red)
    • D3 = (13 × 16) + 3 = 208 + 3 = 211 (Green)
    • FC = (15 × 16) + 12 = 240 + 12 = 252 (Blue)
  3. Result: rgb(125, 211, 252) — a light sky blue

RGB to HSL Conversion (The Algorithm)

This conversion involves normalization, max/min channel identification, and hue angle calculation:

  1. Normalize R, G, B to 0–1 range: r = 125/255 = 0.49, g = 211/255 = 0.827, b = 252/255 = 0.988
  2. Find max and min: max = 0.988 (blue), min = 0.49 (red)
  3. Calculate Lightness: L = (max + min) / 2 = (0.988 + 0.49) / 2 = 73.9%
  4. Calculate Saturation: If max = min, S = 0. Otherwise: S = (max - min) / (1 - |2L - 1|) = 0.498 / 0.522 = 95.4%
  5. Calculate Hue: Since max is blue: H = 60° × ((r - g) / (max - min)) + 240° = 60° × ((0.49 - 0.827) / 0.498) + 240° = ≈ 199.5°

Final result: hsl(199, 95%, 74%)

Using Prescosoft's Color Converter

Manual conversion is educational but tedious in practice. Prescosoft's Color Converter handles all formats instantly including OKLCH and Display-P3:

  1. Open the Color Converter tool
  2. Paste any color value — HEX, RGB, HSL, OKLCH, or named color
  3. All equivalent representations appear instantly in every supported format
  4. Copy any output with one click — formatted for CSS, SCSS, Tailwind config, or JSON

Stop converting colors manually

Paste any color value and get instant conversions across HEX, RGB, HSL, OKLCH, and more.

Convert any color format instantly →

Building a Production Color System with CSS Custom Properties

Regardless of which format you choose, a production color system needs to be centralized, tokenized, and framework-agnostic. Here's how to structure one using the three most common approaches.

CSS Custom Properties (Native)

The most portable approach — works with any framework, no build step required:

:root {

/* Primitive tokens — raw values */

--color-blue-50: #EFF6FF;

--color-blue-100: #DBEAFE;

--color-blue-500: #3B82F6;

--color-blue-600: #2563EB;

--color-blue-900: #1E3A5F;

/* Semantic tokens — purpose-driven */

--color-primary: var(--color-blue-500);

--color-primary-hover: var(--color-blue-600);

--color-bg-subtle: var(--color-blue-50);

}

[data-theme="dark"] {

--color-primary: var(--color-blue-100); /* light text on dark bg */

--color-bg-subtle: var(--color-blue-900);

}

SCSS Variables Equivalent

// _colors.scss

$blue-500: #3B82F6;

$blue-600: #2563EB;

$color-primary: $blue-500;

$color-primary-hover: $blue-600;

// Generate alpha variants

.bg-primary-50 { background: rgba($blue-500, 0.5); }

Tailwind Config Equivalent

// tailwind.config.js

module.exports = {

theme: {

extend: {

colors: {

primary: {

50: '#EFF6FF',

500: '#3B82F6',

600: '#2563EB',

900: '#1E3A5F',

},

},

},

},

}

// Usage: bg-primary-500, text-primary-600, bg-primary-500/50 (opacity modifier)

Tailwind Palette Generation Tip

Use HSL with a single seed hue to generate your entire Tailwind palette. Define a base hue (e.g., 217° for blue), then generate shades 50–950 by varying lightness from 97% down to 15% while keeping saturation around 90%. This guarantees harmonic consistency across all shades. You can use Prescosoft's Color Converter to generate the full scale from a single input, then paste the values directly into your Tailwind config.

Once your color system is in production, you'll apply those same colors across many output formats — not just CSS. You can apply your CSS colors to QR codes, ensuring brand consistency across digital and physical touchpoints.

Build your palette in seconds

Input one color, generate a full accessible palette, export to CSS, SCSS, or Tailwind.

Convert any color format instantly →

Frequently Asked Questions

Is HEX or RGB better for web development?

Neither is universally better. HEX is more compact and ideal for static stylesheets, while RGB is better when you need dynamic manipulation via JavaScript or when working with alpha transparency. Modern CSS supports rgb(r g b / alpha) syntax which combines readability with flexibility. For design tokens, HEX remains the industry standard because design tools like Figma export HEX by default.

Can I use alpha/opacity in HEX colors?

Yes, using 8-digit HEX notation: #RRGGBBAA. For example, #3B82F680 is a blue with 50% opacity (hex 80 = decimal 128, which is 128/255 ≈ 0.502). You can also use 4-digit shorthand: #3BF8 expands to #33BBFF88. Support is excellent in all modern browsers, though IE11 does not support 8-digit HEX.

What's the difference between HSL and HSV/HSB?

HSL (Hue, Saturation, Lightness) and HSV/HSB (Hue, Saturation, Value/Brightness) are different cylindrical color models. In HSL, 100% lightness is always white regardless of hue or saturation. In HSV, 100% brightness with 0% saturation is white, but 100% brightness at full saturation is the pure hue. CSS supports HSL natively but not HSV. Photoshop's color picker uses HSB, so designers converting from Photoshop should be aware of the difference.

Should I use OKLCH in production CSS today?

Yes, if your audience uses modern browsers. OKLCH has been supported in Chrome 111+, Firefox 113+, and Safari 15.4+ (all released in 2023). It is the best perceptual color format for CSS today because it offers uniform lightness, predictable gradients, and access to P3 wide-gamut colors. Use it for new projects and design system tokens, but keep HEX/RGB fallbacks if you support older browsers.

What color format should I use in Tailwind CSS?

Tailwind CSS v3.4+ supports all CSS color formats in custom configurations. The default palette uses HEX values internally. For custom colors, HEX works perfectly in tailwind.config.js. If you want opacity modifiers (like bg-primary/50) to work with custom colors, define them as HSL strings with CSS variables or use the color function syntax.

How do CSS named colors work?

CSS defines 148 named colors (like rebeccapurple, tomato, cornflowerblue) that map to specific HEX values. They are case-insensitive and supported in all browsers. While convenient for quick prototypes, named colors are not recommended for production because they lack precision, don't support alpha channels, and can be ambiguous. Use them only for debugging or throwaway styles.

Ready to master your color workflow?

Convert any color value between HEX, RGB, HSL, OKLCH, and more — instantly, in your browser.

Convert any color format instantly →