Many ways to write the same colour
CSS accepts colours in several notations. They are interchangeable; pick the one that is easiest for the job.
<style>
.swatch { padding: 12px; margin: 6px 0; color: white; font-family: system-ui; }
</style>
<div class="swatch" style="background: tomato">tomato (a named colour)</div>
<div class="swatch" style="background: #ff6347">#ff6347 (hex)</div>
<div class="swatch" style="background: rgb(255 99 71)">rgb(255 99 71)</div>
<div class="swatch" style="background: hsl(9 100% 64%)">hsl(9 100% 64%)</div>All four boxes are the same colour.
Named colours
CSS knows about 140 colour names, from black and white to rebeccapurple and papayawhip. They are great for quick experiments but limited for real designs, where brand colours rarely match a name exactly.
Hex codes
A hex colour is # followed by red, green and blue values, each from 00 (none) to ff (full) in hexadecimal: #ff6347 is red ff (255), green 63 (99), blue 47 (71). When each pair repeats, you can shorten it: #ffcc00 becomes #fc0. Hex is the format designers most often hand over, and what the Image Color Picker gives you when you click a pixel in a photo.
rgb()
rgb(255 99 71) gives the same three values in decimal. You will also see the older comma form, rgb(255, 99, 71); both work in all current browsers.
hsl()
hsl(9 100% 64%) describes colour the way people think about it:
- Hue: the position on the colour wheel, 0 to 360 degrees (0 red, 120 green, 240 blue).
- Saturation: from grey (0%) to vivid (100%).
- Lightness: from black (0%) through the pure colour (50%) to white (100%).
Its superpower is making related shades. Keep the hue and saturation, change only the lightness, and you get a matching palette:
<style>
div { padding: 10px; font-family: system-ui; }
</style>
<div style="background: hsl(210 70% 25%); color: white">hsl(210 70% 25%)</div>
<div style="background: hsl(210 70% 45%); color: white">hsl(210 70% 45%)</div>
<div style="background: hsl(210 70% 65%)">hsl(210 70% 65%)</div>
<div style="background: hsl(210 70% 90%)">hsl(210 70% 90%)</div>Modern browsers also support oklch(), a newer notation in which equal lightness numbers look equally light to the eye. You will meet it in design systems; hsl() is a fine place to start.
Transparency
Every notation can take a fourth value, the alpha channel, from fully transparent to fully solid:
#ff634780(the last pair,80, is about 50%)rgb(255 99 71 / 50%)hsl(9 100% 64% / 0.5)transparent(fully see-through)
Alpha colour versus opacity
<style>
.photo { background: url(https://picsum.photos/seed/cafe/600/200) center/cover; padding: 20px; font-family: system-ui; }
.card { padding: 16px; margin: 8px 0; }
.a { background: rgb(0 0 0 / 60%); color: white; }
.b { background: black; color: white; opacity: 0.6; }
</style>
<div class="photo">
<div class="card a">Alpha background: the text stays solid.</div>
<div class="card b">opacity: the text fades too.</div>
</div>opacity fades the whole element, including its text and children. An alpha value fades only the property it is used in. For a see-through panel with readable text, use an alpha background colour.
currentColor
currentColor means "whatever this element's text colour is". Borders, shadows and SVG icons that use it change automatically when the text colour changes, for example on hover:
.tag {
color: teal;
border: 2px solid currentColor;
}
.tag:hover { color: crimson; } /* the border follows */Contrast: can people read it?
Light grey text on a white background may look elegant on your monitor, but it is hard to read in sunlight, on cheap screens and for anyone with low vision. The Web Content Accessibility Guidelines (WCAG) measure contrast as a ratio from 1:1 (no difference) to 21:1 (black on white). Level AA asks for at least:
- 4.5:1 for normal body text;
- 3:1 for large text (roughly 24px, or about 19px bold) and for icons and borders that carry meaning.
Browser developer tools show the contrast ratio when you inspect a text element's colour, and warn when it is too low. Never rely on colour alone to carry meaning either: an error shown only in red is invisible to many colour-blind users, so add an icon or the word "Error".
Common mistakes
- Low-contrast grey text that looks fine on a bright monitor only.
- Using
opacityfor a translucent background and fading the text by accident. - Typos in hex codes, such as five digits (
#ff634), which the browser ignores. - Colour as the only signal, such as red for errors with no text.
Exercise
Create a "note" box and a "warning" box. Pick one hue for each with hsl(): a very light background (lightness around 92%), a darker border with the same hue (around 45%), and dark text (around 20%). Then give the warning box's border currentColor and set its text colour, so the border follows the text.
Show one possible answer
.note {
background: hsl(210 80% 92%);
border: 2px solid hsl(210 80% 45%);
color: hsl(210 80% 20%);
padding: 12px;
}
.warning {
background: hsl(35 90% 92%);
color: hsl(25 90% 22%);
border: 2px solid currentColor;
padding: 12px;
}Key points
- Colours can be named (tomato), hex (#ff6347), rgb(255 99 71) or hsl(9 100% 64%); they all describe the same colours.
- Add transparency with a fourth value: #ff634780, rgb(255 99 71 / 50%) or hsl(9 100% 64% / 0.5).
- opacity fades a whole element and everything inside it; a transparent colour affects only that one property.
- currentColor reuses the element's text colour, handy for borders and icons.
- Body text needs a contrast ratio of at least 4.5:1 with its background (3:1 for large text).