CSS Colors

Learn every major way to specify color in CSS — named colors, hex, RGB/RGBA, HSL/HSLA, and modern notations like oklch() — and how to control transparency with an alpha channel.

Color is one of the first things you'll style, and CSS gives you more ways to express it than almost any other value type. Knowing when to reach for hex versus HSL versus a modern color function will make you faster at building and adjusting palettes, especially when you need transparency or programmatic color relationships (like 'this, but 20% darker').

Named colors

CSS defines 147 keyword color names — red, tomato, rebeccapurple, cornflowerblue, and so on. They're readable and great for quick prototyping, but limited: there's no way to get a precise custom shade or add transparency using a name alone.

Hexadecimal (hex) colors

Hex colors express red, green, and blue as two-digit hexadecimal numbers (00 to ff) prefixed with #, e.g. #3366cc. Each pair controls one channel: #RRGGBB. There's also a shorthand for colors where each channel's two digits repeat: #36c is shorthand for #3366cc (each character doubles: 3→33, 6→66, c→cc). Hex is by far the most common format for solid, non-transparent colors because design tools export it directly.

Hex also supports an optional alpha channel: #RRGGBBAA or the shorthand #RGBA, where the last pair (or digit) controls opacity from 00 (fully transparent) to ff (fully opaque).

HSL / HSLA — thinking in hue, saturation, lightness

hsl() describes color the way humans intuitively think about it: Hue (0–360°, a position on the color wheel — 0 is red, 120 is green, 240 is blue), Saturation (0%–100%, how vivid vs. gray), and Lightness (0%–100%, how close to black or white). For example hsl(220, 60%, 50%) is a medium blue. HSL is extremely convenient for building color variations — to make something darker, you just lower the lightness percentage; to desaturate it, lower saturation — without recalculating RGB channels by hand. Like rgb(), it accepts a slash-separated alpha: hsl(220 60% 50% / 0.4).

Modern color notation (newer, browser-support-sensitive)

Newer CSS Color Module Level 4 functions like oklch() and lab() describe color in perceptually uniform color spaces — meaning equal numeric changes look like equal visual changes to the human eye, which older models like HSL don't guarantee. oklch(lightness chroma hue) takes lightness (0–1 or a percentage), chroma (roughly how saturated), and hue (0–360°), e.g. oklch(0.7 0.15 250). These modern functions use the space-separated syntax with an optional slash for alpha, matching the newer rgb()/hsl() style: oklch(0.7 0.15 250 / 0.5).

These are genuinely useful for building color scales that look evenly-spaced, but support is newer than hex/rgb/hsl — always check current browser support before relying on them for a production site's primary color system, and consider providing a fallback declaration (browsers use the last valid one they understand, so listing a hex fallback before an oklch() rule is a safe pattern).

Transparency via the alpha channel

Every color function above supports an alpha channel to control opacity: 0 (or 0%) is fully invisible, 1 (or 100%) is fully opaque. Alpha is different from the separate opacity CSS property — opacity fades the entire element (including its children and borders), while a color's own alpha channel only affects that one color value (e.g. just the background, leaving text fully opaque).

Color notation formats

The comma-separated legacy syntax (rgba(), hsla()) and the modern space-separated syntax both work for rgb()/hsl() — the slash for alpha is only valid in the modern syntax. Always provide a fallback color before an oklch()/lab() declaration if you need to support older browsers.

/* Named color */
color: tomato;

/* Hex */
color: #3366cc;
color: #36c;            /* shorthand */
color: #3366cc80;       /* with alpha (~50% opacity) */

/* RGB / RGBA */
color: rgb(51, 102, 204);
color: rgba(51, 102, 204, 0.5);
color: rgb(51 102 204 / 50%);   /* modern space + slash syntax */

/* HSL / HSLA */
color: hsl(220, 60%, 50%);
color: hsla(220, 60%, 50%, 0.5);
color: hsl(220 60% 50% / 50%);  /* modern space + slash syntax */

/* Modern: oklch() — newer, check browser support */
color: oklch(0.7 0.15 250);
color: oklch(0.7 0.15 250 / 50%);

Code Examples

Because HSL separates lightness from hue and saturation, creating a consistent 'darker on hover' effect is as simple as subtracting from the lightness value.

Using rgba() (or the modern rgb() with a slash) lets you darken a backdrop without affecting the opacity of child text — unlike the opacity property, which would fade everything inside the element too.

4-digit hex shorthand (#RGBA) expands each character by doubling it, same as 3-digit shorthand — the 4th character controls alpha.

.btn {
  background: hsl(220, 70%, 45%);
}

.btn:hover {
  background: hsl(220, 70%, 35%);  /* same hue & saturation, just darker */
}
.overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);  /* black at 60% opacity */
}

.overlay .text {
  color: white;   /* stays fully opaque — alpha only affected the background */
}
.badge {
  border: 1px solid #333;       /* shorthand for #333333 */
  background: #f0f4;            /* shorthand for #ff0044ff -> wait, careful: */
  /* #f0f4 expands to #ff0044ff: f->ff, 0->00, f->ff, 4->44 */
}

Important Rules

Hex, RGB, and HSL can all represent identical colors — pick the format that's easiest to reason about for the task (HSL for adjusting lightness/saturation, hex for pasting from design tools).

The modern space-separated syntax with a trailing slash (color-space value1 value2 value3 / alpha) works across rgb(), hsl(), and newer functions like oklch().

An element's own opacity property fades the whole element and its children; a color's alpha channel only fades that specific color value.

Check current browser support before depending on oklch()/lab() for critical brand colors, and supply a fallback declaration.

Design systems and color

Most production design systems store colors as CSS custom properties defined in HSL or the newer OKLCH, precisely because it's easy to generate a whole shade scale (50, 100, 200...900) by only changing the lightness value while keeping hue and saturation constant — producing visually consistent, evenly-stepped palettes without a design tool..modal-backdrop { background: black; opacity: 0.5; }.modal-backdrop { background: rgba(0, 0, 0, 0.5); }

Setting opacity on the backdrop element fades any child content (like a close button or text) placed inside it too. Using an alpha channel on the background color keeps children fully opaque.

color: #3366cc80 /* trying to make text mostly transparent */ color: opacity: 0.8;

Alpha in hex is specified as a 2-digit hex value from 00–ff, not a decimal like 0.8. 80% opacity is roughly CC in hex (204/255), not the literal characters '80'.

[Choose the Correct Syntax] Which of these correctly sets a background color to medium blue at 30% opacity using modern CSS color syntax? A. background: rgb(51, 102, 204, 30%); B. background: rgb(51 102 204 / 30%); C. background: rgb(51-102-204-30%); D. background: #3366cc(30%);

B. background: rgb(51 102 204 / 30%); — The modern rgb() syntax separates color channels with spaces and adds alpha after a slash: rgb(51 102 204 / 30%). Option A mixes the legacy comma syntax with a percentage alpha in the wrong position (missing the slash) which is invalid; options C and D are not valid CSS syntax at all.

You have a brand color hsl(280, 65%, 45%). Write three CSS rules: the base color, a lighter 'hover' variant, and a 40%-opacity version suitable for a background wash — all using HSL.

base: color: hsl(280, 65%, 45%); hover: color: hsl(280, 65%, 55%); (increased lightness) wash: background: hsl(280 65% 45% / 0.4); (or hsla(280, 65%, 45%, 0.4))

Adjust only the lightness percentage for the hover variant, and add a fourth alpha value (or use hsla()) for the wash.