HEX vs RGB vs HSL: Which CSS Color Format Should You Use and When
A practical breakdown of HEX, RGB, and HSL color formats — with real code examples, browser support data, and clear rules for picking the right one in every situation.
HEX vs RGB vs HSL: Which CSS Color Format Should You Use and When
Three color syntaxes exist in CSS, and most developers pick whichever they learned first. That works until it doesn't — until you need to animate an opacity value, darken a brand color by 15%, or make sense of a design handoff full of HSL values. Knowing when each format fits saves real debugging time.
What Each Format Actually Stores
HEX encodes red, green, and blue as a six-digit base-16 string: #1a73e8. An optional two-digit alpha suffix (#1a73e8cc) was added in CSS Colors Level 4. The three-digit shorthand (#1ae) is valid when every pair repeats (#11aaee).
RGB is the same red-green-blue model written in decimal: rgb(26, 115, 232). The modern CSS syntax also accepts a slash-separated alpha: rgb(26 115 232 / 0.8).
HSL describes hue (0°–360°), saturation (0%–100%), and lightness (0%–100%): hsl(217, 80%, 51%). Because the three numbers map to human perception of color — not machine memory — it is the only format where you can meaningfully edit a value without a color picker open.
All three describe the same color space (sRGB). The choice of format does not affect rendering — only readability and maintainability.
When HEX Is the Right Call
HEX is the dominant format in design tools, brand guidelines, and copy-pasted snippets. It's the shortest way to specify an opaque color, and almost every color-picker widget outputs it by default.
I default to HEX for any color I'm not going to compute — static backgrounds, border colors, text colors that ship verbatim from a design system. A token like --color-brand: #1a73e8 is five characters shorter than its RGB equivalent and instantly scannable in a diff.
Where HEX breaks down: you cannot manipulate it in plain CSS. If you want a 20% lighter version of #1a73e8 you need color-mix() or a preprocessor. HEX alpha (#1a73e8cc) is supported in all modern browsers since Safari 12 (2018), but many developers still find it harder to read than an explicit decimal opacity.
Use HEX when: copying a color from Figma or a brand palette, writing static CSS without CSS custom properties, or minimizing character count in hand-rolled stylesheets.
When RGB Fits Better
RGB shines in one scenario: dynamic alpha. Before the CSS color() function arrived, rgba(26, 115, 232, 0.5) was the standard way to add transparency without SCSS functions, and it reads clearly.
More concretely: I was building a tooltip overlay last year where the background needed to respect both dark mode and variable opacity. Storing the base as --color-brand-rgb: 26 115 232 let me write rgb(var(--color-brand-rgb) / var(--tooltip-alpha)) in a single line — no extra custom properties, no fallback needed.
The modern space-separated syntax (rgb(26 115 232 / 0.8)) has 97.5% global browser support as of mid-2026 per caniuse.com, so the comma-based legacy form is no longer required for compatibility.
Use RGB when: you need to compose colors from stored channel values at runtime, or when alpha changes dynamically via CSS custom properties or JavaScript.
When HSL Wins
HSL is the format where humans have an intuitive editing advantage. The lightness axis goes from 0% (black) to 100% (white), with the fully saturated hue at roughly 50%. This means:
hsl(217, 80%, 51%)is your base brand bluehsl(217, 80%, 70%)is obviously lighterhsl(217, 80%, 35%)is obviously darker
No conversion tool needed. No trial and error. You can read a palette and understand its relationships without opening a color picker.
A real example: I was asked to generate five tints from a brand color #1a73e8. Converting to HSL gives hsl(217, 80%, 51%). I then produced the full tint scale by shifting lightness alone:
--blue-100: hsl(217, 80%, 93%);
--blue-300: hsl(217, 80%, 75%);
--blue-500: hsl(217, 80%, 51%); /* base */
--blue-700: hsl(217, 80%, 35%);
--blue-900: hsl(217, 80%, 18%);
Input: #1a73e8 → hsl(217, 80%, 51%). Output: five design-system tokens, all coherent, written in under a minute. No color-mixing math, no SCSS lighten() function.
The one HSL limitation worth knowing: equal numeric distances in lightness do not produce equal perceived brightness differences. Jumping from 50% to 70% looks much smaller than jumping from 70% to 90% — a perceptual quirk. For fine-grained color systems this matters. (OKLab-based formats like oklch() handle perception better, but browser support is still narrowing as of 2026.)
Use HSL when: designing a color palette from scratch, building a theming system where you want colors to feel related, or any time a designer asks "can you make that 10% darker?"
Format Conversion in Practice
The conversions between formats are lossless for sRGB values. #1a73e8, rgb(26, 115, 232), and hsl(217, 80%, 51%) are the same pixel.
For quick one-off conversions I use the CSS Color Format Converter — it takes any of the three inputs and outputs the others, plus oklch() and Tailwind-compatible tokens in one step. For projects where I need to audit the entire palette, Color Converter handles bulk conversions including CMYK and HSV.
If you're picking colors for a UI and need to check that your HSL-based tints still meet WCAG contrast requirements, plug each combination into a contrast checker after you finalize the palette. A lighter tint that looks readable on screen can fail the 4.5:1 ratio required for body text under WCAG 2.2.
The Decision Rule
One sentence per scenario:
- Static design tokens copied from Figma? HEX.
- Alpha compositing at runtime via CSS variables? RGB.
- Building or editing a color palette directly in CSS? HSL.
- Perceptually uniform dark mode or accessibility-grade theming? Consider
oklch().
Most production codebases mix all three, which is fine. The mistake worth avoiding is using HEX everywhere and then reaching for a CSS preprocessor just to do darken(#1a73e8, 10%) — that's the job HSL was built for.
Made by Toolora · Updated 2026-06-28