Skip to content
AgileLogics
6 min read

Colors

Prerequisites: Basic selectors

CSS accepts colors in several formats. All of these are the same orange-red:

.a { color: orangered; }
.b { color: #ff4500; }
.c { color: #f40; }
.d { color: rgb(255 69 0); }
.e { color: hsl(16 100% 50%); }

(#f40 is shorthand for #ff4400 — very close, but not identical.)

Format Notes
Named colors 148 names like tomato, rebeccapurple, transparent, plus currentColor
Hex #rrggbb Red, green, blue in hexadecimal (00–ff); #rgb short form; #rrggbbaa adds alpha
rgb() Red, green, blue as 0–255 (or percentages)
hsl() Hue (0–360 degrees on the color wheel), saturation, lightness
oklch() Perceptual lightness, chroma, hue — best for building palettes (Level 3)

Transparency

Add alpha after a slash, from 0 (transparent) to 1 (opaque), or as a percentage:

.overlay { background: rgb(0 0 0 / 50%); }
.tint { background: hsl(210 80% 50% / 0.15); }
.glass { background: #ffffff80; }

You'll also see the older comma syntax, rgba(0, 0, 0, 0.5) — it still works everywhere. opacity: 0.5 is different: it fades the whole element, including its text and children.

What the browser stores

<style>
  .a { color: orangered; }
  .b { color: #f40; }
  .c { color: hsl(16 100% 50%); }
  .d { color: rgb(0 0 0 / 50%); }
  .e { color: #ff450080; }
  .f { color: teal; border: 2px solid currentColor; }
</style>
<p class="a">a</p><p class="b">b</p><p class="c">c</p>
<p class="d">d</p><p class="e">e</p><p class="f">f</p>
<script>
  for (const p of document.querySelectorAll("p")) {
    const s = getComputedStyle(p);
    console.log(p.className, s.color, p.className === "f" ? s.borderTopColor : "");
  }
</script>
a rgb(255, 69, 0) 
b rgb(255, 68, 0) 
c rgb(255, 68, 0) 
d rgba(0, 0, 0, 0.5) 
e rgba(255, 69, 0, 0.5) 
f rgb(0, 128, 128) rgb(0, 128, 128)
  • hsl(16 100% 50%) is exactly rgb(255, 68, 0) — within one step of orangered.
  • currentColor means "this element's color", so the border follows the text color automatically. It's the default for border-color too.

Why HSL is handy

Keep the hue, change lightness for shades:

:root {
  --brand: hsl(210 80% 45%);
  --brand-light: hsl(210 80% 92%);
  --brand-dark: hsl(210 80% 25%);
}

(--brand is a custom property, used with var(--brand) — Level 2.)

Contrast

Text needs enough contrast with its background to be readable. WCAG asks for a ratio of at least 4.5:1 for normal text and 3:1 for large text. Light gray on white is the most common failure. DevTools shows the ratio when you click a color swatch in the Styles panel.

Our Color Picker, HEX to RGB, and RGB to HEX tools convert between formats.

Practice

Write a rule for .alert with dark red text on a very light red background, and a 1-pixel border in the text color at 40% opacity.

Show solution
.alert {
  color: hsl(0 70% 30%);
  background: hsl(0 100% 96%);
  border: 1px solid hsl(0 70% 30% / 40%);
}