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.
#rgb expands each digit to two identical digits.rgba form adds an alpha (transparency) channel from 0 (invisible) to 1 (fully opaque).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).
/* 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 */
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).
/* 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.
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.
/* 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(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).
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 */
}
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.
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.
.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.
/* 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;
}
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:
.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.
/* 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));
/* 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);
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.
/* 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 / Format | What it does | Key values |
|---|---|---|
color | Text (foreground) colour | Any colour format · inherit · currentColor |
background-color | Solid background fill | Any colour format · transparent |
background-image | Image or gradient behind content | url('path') · linear-gradient() · radial-gradient() |
background-size | How the bg image is scaled | cover · contain · px · % |
background-position | Where bg image is anchored | center · top right · 50% 25% |
background-repeat | Whether bg image tiles | no-repeat · repeat · repeat-x · repeat-y |
background | Shorthand for all background properties | colour url() position/size repeat |
opacity | Transparency of whole element | 0 (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.
<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.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..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); }
.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.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..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%);
}
<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).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.* { 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;
}
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.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.* { 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().