Colours

🎨 Chapter 4 — Colors and Backgrounds

Colour is one of the most immediately visible aspects of any design. CSS gives you several ways to express a colour — named values, hexadecimal, RGB, and HSL — and a rich set of background properties that go well beyond a simple solid fill. This chapter covers all the colour formats you will encounter and how to use them on text and backgrounds, including gradients and background images.

1 — Colour Formats

CSS accepts colours in four main formats. They are interchangeable — every colour property accepts any format. You will often use different formats for different purposes in the same stylesheet.

Named Colours
red · blue · coral · tomato
CSS defines 140+ named colours. Good for quick prototyping and well-known colours, but limited and imprecise for professional design work.
Hexadecimal
#rrggbb · #rgb
The most common format in practice. A 6-digit hex code (0–9, a–f) encodes red, green, and blue channels. The shorthand #rgb expands each digit to two identical digits.
RGB / RGBA
rgb(r, g, b) · rgba(r, g, b, a)
Expresses each channel as a number 0–255. The rgba form adds an alpha (transparency) channel from 0 (invisible) to 1 (fully opaque).
HSL / HSLA
hsl(h, s%, l%) · hsla(h, s%, l%, a)
Hue (0–360°), Saturation (0–100%), and Lightness (0–100%). Much more intuitive for humans — great for creating colour variations and themes.

2 — Hexadecimal Colours

Hex colours are written with a # followed by six characters in pairs: the first pair is red, the second green, the third blue. Each pair runs from 00 (none) to ff (full — equal to 255 in decimal).

🎨 CSS — Hex colour examples
/* Full 6-digit hex */ color: #ff0000; /* red — ff red, 00 green, 00 blue */ color: #00ff00; /* green — 00 red, ff green, 00 blue */ color: #0000ff; /* blue — 00 red, 00 green, ff blue */ color: #ffffff; /* white — all channels full */ color: #000000; /* black — all channels empty */ color: #4f8ef7; /* a mid-blue — red 79, green 142, blue 247 */ /* 3-digit shorthand — each digit doubles (#abc = #aabbcc) */ color: #f00; /* same as #ff0000 */ color: #fff; /* same as #ffffff */ color: #333; /* same as #333333 — a dark grey */ /* 8-digit hex — adds alpha channel (last two digits: 00=transparent, ff=opaque) */ background: #4f8ef780; /* ~50% transparent blue */
#f00
#f60
#ffd580
#7ecfa0
#4f8ef7
#c9a8ff
#e2e4ec
#333
💡 Use your editor's colour picker. VS Code and most other editors show an inline colour preview next to hex values and pop up a colour picker when you click it. You rarely need to write hex codes from memory — design tools like Figma export them for you, and the DevTools colour picker lets you sample any colour on screen.

3 — RGB and RGBA

RGB expresses colour as three numbers — red, green, and blue — each ranging from 0 to 255. The rgba function adds a fourth value: alpha, which controls transparency. Alpha ranges from 0 (fully transparent) to 1 (fully opaque).

🎨 CSS — RGB and RGBA
/* rgb() — same colours as the hex examples above */ color: rgb(255, 0, 0); /* red */ color: rgb(79, 142, 247); /* #4f8ef7 — same blue as above */ color: rgb(51, 51, 51); /* #333333 — dark grey */ /* rgba() — adding transparency */ background-color: rgba(79, 142, 247, 1.0); /* fully opaque */ background-color: rgba(79, 142, 247, 0.5); /* 50% transparent */ background-color: rgba(79, 142, 247, 0.1); /* barely visible tint */ background-color: rgba(0, 0, 0, 0.4); /* dark overlay on images */

The alpha channel is particularly useful for:

  • Overlays — a semi-transparent dark layer over an image to make text readable.
  • Tinted backgrounds — a very low-opacity colour tint for hover states or highlighted sections.
  • Shadows and glows — subtle, blended effects.
1.0
0.75
0.5
0.25
0.1

4 — HSL and HSLA

HSL stands for Hue, Saturation, Lightness. Unlike RGB and hex which are machine-oriented, HSL maps to how humans think about colour — making it far easier to create harmonious palettes and adjust colours intuitively.

Hue — 0–360°
0° = red · 120° = green · 240° = blue · 360° = red again
Saturation — 0–100%
0% = grey · 100% = fully saturated (vivid)
Lightness — 0–100%
0% = black · 50% = normal · 100% = white
🎨 CSS — HSL in practice
/* hsl(hue, saturation, lightness) */ color: hsl(220, 90%, 63%); /* vivid blue (~#4f8ef7) */ color: hsl(220, 90%, 45%); /* darker blue — same hue, lower lightness */ color: hsl(220, 90%, 80%); /* lighter blue — same hue, higher lightness */ color: hsl(220, 20%, 63%); /* muted blue — same hue, lower saturation */ color: hsl(220, 0%, 63%); /* grey — zero saturation */ /* Creating a palette from a single hue */ .btn-primary { background: hsl(220, 90%, 55%); } /* normal */ .btn-primary:hover { background: hsl(220, 90%, 45%); } /* darker */ .btn-primary:active { background: hsl(220, 90%, 35%); } /* darkest */ /* hsla() — same as hsl with transparency */ background: hsla(220, 90%, 63%, 0.2); /* faint blue tint */
HSL shines when you need colour variations. Change only the lightness to get shades of the same colour — no need to calculate new hex codes.
Modern CSS colour syntax. Modern browsers also support a space-separated syntax without commas: hsl(220 90% 63%) and rgb(79 142 247). For alpha you use a slash: hsl(220 90% 63% / 0.5). Both forms work — the comma version is more widely recognised, so it is used throughout this chapter.

5 — The color Property

The color property sets the foreground colour of an element — most visibly its text. It is also used by borders that have color: currentColor (a special value that refers to the element's current text colour).

🎨 CSS — Setting text colour
body { color: #e2e4ec; /* default text colour for the whole page */ } h1 { color: #ffffff; /* headings are brighter than body text */ } .muted { color: #7a7f96; /* secondary / caption text */ } .error { color: #f08080; /* error state */ } .success { color: #7ecfa0; /* success state */ } /* currentColor inherits the element's text colour */ .icon-border { color: #4f8ef7; border: 2px solid currentColor; /* border matches the text colour */ }
colour is inherited. Child elements inherit the color value of their parent unless they set their own. Setting color on body gives you a sensible default for all text on the page — then you only override where needed.

6 — background-color

The background-color property fills the element's content and padding areas with a solid colour. The default is transparent — most elements have no background colour until you set one.

🎨 CSS — Background colours
body { background-color: #0d0d0d; } /* near-black page background */ .card { background-color: #1a1d27; } /* slightly lighter card */ .badge { background-color: #4f8ef7; } /* solid blue badge */ .tint { background-color: rgba(79, 142, 247, 0.1); } /* subtle tint */ /* transparent is the default — explicit reset */ .no-bg { background-color: transparent; }

7 — Background Images

CSS can place an image behind an element's content using background-image. The image tiles by default and can be controlled with several companion properties.

🎨 CSS — Background image properties
.hero { background-image: url('images/hero.jpg'); /* How the image is sized */ background-size: cover; /* fills the element, may crop */ /* background-size: contain; */ /* fits inside, may leave gaps */ /* background-size: 400px 200px; */ /* exact size */ /* Where the image is anchored */ background-position: center; /* centre of the element */ /* background-position: top right; */ /* background-position: 50% 25%; */ /* Whether the image repeats */ background-repeat: no-repeat; /* no tiling */ /* background-repeat: repeat; */ /* tile in both directions */ /* background-repeat: repeat-x; */ /* tile horizontally only */ /* Whether image scrolls with page or stays fixed */ background-attachment: scroll; /* moves with element (default) */ /* background-attachment: fixed; */ /* parallax-style, stays put */ min-height: 400px; }

background shorthand

All background properties can be combined into a single background shorthand. The order is flexible but the convention is: colour image position/size repeat attachment.

🎨 CSS — background shorthand
/* Longhand */ .hero { background-color: #1a1d27; background-image: url('hero.jpg'); background-position: center; background-size: cover; background-repeat: no-repeat; } /* Shorthand equivalent — size comes after position with a slash */ .hero { background: #1a1d27 url('hero.jpg') center / cover no-repeat; } /* Fallback colour — shows if image fails to load */ .hero { background: #0d0d0d url('hero.jpg') center / cover no-repeat; }
Always include a fallback background-color when using a background image. If the image fails to load or takes a moment, the colour shows instead.

Stacking a colour overlay on an image

A common pattern — darkening an image so text placed on top remains readable:

🎨 CSS — Semi-transparent overlay technique
.hero { /* Stack: dark overlay on top of the image */ background-image: linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)), url('hero.jpg'); background-size: cover; background-position: center; color: white; }

8 — Gradients

CSS gradients are generated images — not colour values — so they are used with background-image, not background-color. The two most common types are linear and radial.

🎨 CSS — Linear gradients
/* Left to right (default direction) */ background-image: linear-gradient(#4f8ef7, #c9a8ff); /* Specify direction */ background-image: linear-gradient(to right, #4f8ef7, #c9a8ff); background-image: linear-gradient(to bottom right, #4f8ef7, #c9a8ff); background-image: linear-gradient(135deg, #4f8ef7, #c9a8ff); /* Multiple colour stops */ background-image: linear-gradient(to right, #f08080, #ffd580, #7ecfa0); /* Gradient with transparency — fades image to transparent */ background-image: linear-gradient(to bottom, transparent, rgba(0,0,0,0.8));
🎨 CSS — Radial gradients
/* Radiates outward from centre by default */ background-image: radial-gradient(#4f8ef7, #0d0d0d); /* Specify shape and size */ background-image: radial-gradient(circle at center, #4f8ef7, #0d0d0d); background-image: radial-gradient(ellipse at top, #c9a8ff, #0d0d0d);
💡 Don't write gradients by hand. Tools like CSS Gradient Generator (search "css gradient generator") let you design gradients visually and copy the CSS. The syntax is powerful but verbose — use a tool until it becomes second nature.

9 — opacity

The opacity property makes an entire element (and all its children) transparent. It differs from the alpha channel in rgba/hsla: those affect only one colour value, while opacity affects the whole element including its text, borders, and children.

🎨 CSS — opacity vs rgba alpha
/* opacity: affects the entire element including text */ .faded-card { opacity: 0.5; /* element + all children are 50% transparent */ } /* rgba: affects only the background, text remains opaque */ .tinted-card { background-color: rgba(79, 142, 247, 0.15); color: #e2e4ec; /* text is still fully opaque */ } /* Common use for opacity: disabled states */ .btn:disabled { opacity: 0.4; cursor: not-allowed; }

10 — Quick Reference

Property / FormatWhat it doesKey values
colorText (foreground) colourAny colour format · inherit · currentColor
background-colorSolid background fillAny colour format · transparent
background-imageImage or gradient behind contenturl('path') · linear-gradient() · radial-gradient()
background-sizeHow the bg image is scaledcover · contain · px · %
background-positionWhere bg image is anchoredcenter · top right · 50% 25%
background-repeatWhether bg image tilesno-repeat · repeat · repeat-x · repeat-y
backgroundShorthand for all background propertiescolour url() position/size repeat
opacityTransparency of whole element0 (invisible) to 1 (opaque)
Colour formats Ways to express a colour red · #4f8ef7 · rgb(79,142,247) · rgba(…,0.5) · hsl(220,90%,63%)

✏️ Exercises

Each exercise builds a visual component. Open the file in your browser and compare the result to the description — small tweaks to lightness or alpha are a great way to develop your colour intuition.

Exercise 1
Create a row of five coloured chips — small <span> elements styled as inline pills. Colour them using five different formats: a named colour, a hex code, an RGB value, an HSL value, and an RGBA value with 70% opacity. Give each a white text label so you can see the colour format used.
Hint: use display: inline-block; padding: 4px 12px; border-radius: 999px; to create the pill shape. Make sure each has enough contrast with its text — dark text on light backgrounds, white text on dark ones.
CSS
.chip { display: inline-block; padding: 4px 14px; border-radius: 999px; color: white; font-family: system-ui, sans-serif; font-size: 0.85rem; margin-right: 6px; } .chip-named { background-color: steelblue; } .chip-hex { background-color: #7ecfa0; } .chip-rgb { background-color: rgb(201, 168, 255); } .chip-hsl { background-color: hsl(30, 90%, 60%); } .chip-rgba { background-color: rgba(240, 128, 128, 0.7); }
Exercise 2
Build a status badge system using HSL colours. Create three badge classes — .badge-success, .badge-warning, and .badge-error — using the same hue for both the background and border, but vary the lightness and saturation to create a tinted background with a stronger border. All three should use hsl() values.
Hint: for success try hsl(145, 60%, ...) — use a low lightness (~20%) for the background and higher lightness (~45%) for the text and border. This creates the "tinted card with coloured accent" pattern common in UI frameworks.
CSS
.badge { display: inline-block; padding: 4px 12px; border-radius: 4px; font-family: system-ui, sans-serif; font-size: 0.82rem; font-weight: 600; border-width: 1px; border-style: solid; } .badge-success { background-color: hsl(145, 50%, 15%); color: hsl(145, 60%, 55%); border-color: hsl(145, 50%, 30%); } .badge-warning { background-color: hsl(38, 80%, 15%); color: hsl(38, 90%, 60%); border-color: hsl(38, 70%, 35%); } .badge-error { background-color: hsl(0, 60%, 15%); color: hsl(0, 80%, 65%); border-color: hsl(0, 55%, 35%); }
Exercise 3
Create a hero section — a full-width <div> at least 300px tall — with a two-colour linear gradient as its background. Place a heading and a short paragraph inside it. Make sure the text is readable by choosing gradient colours with enough contrast against white text. Experiment with the gradient direction using both keyword directions (to bottom right) and a degree angle (135deg).
Hint: dark colours work best for readability. Try linear-gradient(135deg, #0d0d0d, #1a1d27) as a starting point, then experiment. Use display: flex; align-items: center; justify-content: center; to centre the text inside the hero.
CSS
* { box-sizing: border-box; margin: 0; padding: 0; } .hero { background-image: linear-gradient(135deg, #0d0d0d, #1a1d27 60%, #12204a); min-height: 360px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 40px; color: white; font-family: Georgia, serif; } .hero h1 { font-size: 2.5rem; color: #4f8ef7; margin-bottom: 12px; } .hero p { color: #a0a4b8; max-width: 520px; }
Exercise 4
Build a card that uses rgba layering. Create a <div class="glass-card"> on a colourful gradient background (set on body). Give the card itself a semi-transparent white background using rgba(255, 255, 255, 0.1), a subtle white border at low opacity, and a slight backdrop-filter: blur(10px) for a frosted-glass effect. The card should show the gradient through it while remaining readable.
Hint: backdrop-filter: blur(10px) blurs whatever is behind the element — this is what creates the frosted-glass look. It requires the element to have a semi-transparent background to be visible. Note: not supported in older browsers.
CSS
* { box-sizing: border-box; margin: 0; padding: 0; } body { background-image: linear-gradient(135deg, #4f8ef7, #c9a8ff, #7ecfa0); min-height: 100vh; display: flex; align-items: center; justify-content: center; font-family: Georgia, serif; } .glass-card { background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.25); border-radius: 12px; padding: 36px 40px; max-width: 420px; backdrop-filter: blur(10px); color: white; text-align: center; }

This "glassmorphism" style is popular in modern UI design. The key ingredients are a semi-transparent background, a subtle white border, and backdrop-filter: blur().