TFreeToolsHub

HEX, RGB, and HSL: Choosing the Right Color Format

ToolHub Team
CSSDesignColor

Three ways to describe color in CSS, and the situations where each one wins.

Ad placeholder — enabled when AdSense approved

CSS gives you three main ways to describe a color: hex, RGB, and HSL. A hex color is a hash followed by six hexadecimal digits, where the first two represent red, the next two green, and the last two blue, like #ff6600. A three-digit shorthand expands each digit, so #f60 is equivalent to #ff6600. RGB functions take three numbers from 0 to 255, as in rgb(255, 102, 0), and an optional alpha channel as a fourth value between 0 and 1, as in rgba(255, 102, 0, 0.5). HSL takes three values too, but they describe hue as an angle from 0 to 360, saturation as a percentage, and lightness as a percentage, as in hsl(20, 100%, 50%). All three formats describe the same sRGB color space, so any color you can write in one you can convert to the others without loss. The choice is mostly about readability and what you need to do with the value.

Hex is the workhorse of web color. It is compact, unambiguous, and supported everywhere, including places that historically did not accept CSS functions, like the color attribute in SVG or older attributes on form elements. The six-digit form is the most common, and the three-digit shorthand is convenient for colors where each channel's two digits are the same. Hex is also the format that survives best in configuration files, build scripts, and JSON, because it is a single string with no spaces or commas to escape. When you are working with CSS custom properties, hex is the easiest value to swap out at runtime. The main drawback is that hex does not natively express alpha, so you have to use the eight-digit form like #ff660080, which is less widely understood, or fall back to rgba. Hex is also harder to read when you want to make small perceptual adjustments, since the relationship between the digits and the perceived color is not intuitive.

RGB and RGBA describe colors by their red, green, and blue components, which mirrors how displays emit light. The format is verbose compared to hex, but it has one major advantage: native support for an alpha channel. RGBA takes a fourth value between 0 and 1, or a percentage, that controls opacity, which is exactly what you need for translucent overlays, hover states, and layered backgrounds. RGB and hex are functionally equivalent for opaque colors, since rgb(255, 102, 0) and #ff6600 describe the same color, so the choice between them is often a matter of team convention. RGBA's real value shows up in design systems where you need to tint a brand color at several opacities; expressing it as rgba(var(--brand), 0.2) is clearer than the eight-digit hex equivalent. The modern syntax also allows space-separated values like rgb(255 102 0 / 50%), which is more readable and aligns with the new color functions.

HSL is where color becomes intuitive. Hue is an angle on the color wheel, saturation is how vivid the color is, and lightness is how bright it is. Want a darker version of a brand color? Drop the lightness by 10 percent. Want a softer version? Lower the saturation. Want a complementary color? Add 180 to the hue. These are operations you can do in your head, which is impossible with hex or RGB. HSL really shines when generating color palettes: a monochromatic palette is just the same hue at different lightness levels, an analogous palette is hues within 30 degrees of each other, and a triadic palette is hues 120 degrees apart. Most design systems that expose theming to users do so through HSL or HSL-derived tokens, because designers think in hue and saturation, not in hex codes. The one thing to watch is that HSL lightness is not perceptually uniform, so a 50 percent lightness yellow looks very different from a 50 percent lightness blue.

Modern CSS introduces the color() function, which lets you specify colors in any supported color space using a consistent syntax. You can write color(display-p3 1 0.4 0) to target the Display-P3 wide-gamut space used by modern Apple displays, or color(rec2020 ...) for an even wider space. This matters because sRGB, the space that hex and HSL describe, cannot represent the most saturated reds, greens, and cyans that current hardware can display. If you are building for HDR-capable screens or working with photography, the wider gamut lets you use colors that simply did not exist on the web before. For most projects, sticking with sRGB is still the safe default, because every display supports it and the colors will look consistent. When you do want to opt in, use color() with a fallback for browsers that do not support it yet, and test on actual hardware, since the difference between P3 and sRGB is most visible on saturated colors and is easy to overestimate on a non-P3 monitor.

The format you pick should match the job. For a simple static website with a fixed palette, hex is the right choice: it is short, universal, and easy to copy from a design file. For semi-transparent overlays, hover states, or anywhere you need to control opacity inline, RGBA is clearer than the eight-digit hex form. For design systems, especially those that expose theming or generate palettes programmatically, HSL is the best fit because the values map to how designers think. Many component libraries use CSS custom properties in HSL, like hsl(var(--brand-h) var(--brand-s) var(--brand-l)), so they can be overridden per theme without rewriting every rule. If you are working with wide-gamut content, color() with a P3 space is appropriate, but make sure you provide an sRGB fallback. There is no single best format; the right choice depends on whether you are hand-writing a value, generating it, or overriding it at runtime.

Color contrast is an accessibility requirement, not a design preference. The Web Content Accessibility Guidelines specify a minimum contrast ratio of 4.5:1 for normal text and 3:1 for large text, with stricter 7:1 and 4.5:1 ratios for AAA conformance. Failing contrast is one of the most common accessibility issues on the web, and it is usually a matter of choosing a slightly darker shade or a different background. The format you write the color in does not affect the ratio, but HSL makes it easy to nudge lightness in 5 percent steps until you meet the threshold. When you are designing a system, define your palette in HSL and test every text-on-background combination with a contrast checker. Keep in mind that contrast is measured against the perceived luminance, so two colors that look very different can still fail the ratio. Automated tools like Lighthouse and axe will flag failures, but designing for contrast from the start is faster than fixing it later.

A good color workflow combines a few tools. A picker like the one built into your browser's DevTools lets you sample colors from anywhere on the page and copy them in any format. A contrast checker, whether built into DevTools or as a separate site, tells you instantly whether a pair meets WCAG. A palette generator like Coolors or the HSL-based tools in Figma helps you build a coherent set of colors with consistent hue and saturation. A converter is useful when a design file gives you hex but your system expects HSL, or vice versa; most modern tools handle this conversion automatically, but a standalone converter is handy for quick checks. For wide-gamut work, a tool that shows you the P3 versus sRGB difference side by side helps you decide whether the wider gamut is worth the added complexity. The goal is to pick tools that get out of your way and let you focus on the design decisions.