Skip to main content

🎨 Colors, Backgrounds, and Gradients

Colour is one of the most powerful tools in visual communication — it sets mood, builds hierarchy, and carries brand. This lesson covers every way CSS lets you name a colour, how to paint element backgrounds, and how to generate rich gradients with zero image files.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Specify colour in hex, RGB(A), HSL(A), and modern formats, and pick the right one for the job
  • Explain the HSL model and use it to build harmonious colour schemes
  • Control backgrounds with background-image, -repeat, -position, -size, and the shorthand
  • Create linear, radial, and conic gradients, including repeating variants
  • Meet WCAG contrast requirements and keep backgrounds performant

Estimated Time: 40–50 minutes  •  Difficulty: Beginner

Hands-on: Build a pure-CSS hero section with a layered gradient background and readable text.

In This Lesson

Why Colour Matters

Colour establishes brand identity, creates visual hierarchy, improves usability, and sets emotional tone. A film director uses colour grading to steer your mood and attention; a web designer uses CSS colour the same way — to make an interface feel cohesive, intuitive, and alive.

💬 "Color does not add a pleasant quality to design — it reinforces it." — Pierre Bonnard. Colour works best in service of structure, not as decoration bolted on afterward.

CSS applies colour in many places: text (color), fills (background-color), edges (border-color), and effects (box-shadow, text-shadow). First, though, we need to agree on how to write a colour.

CSS Colour Formats

CSS accepts several notations for the same colour. They differ in readability, whether they support transparency, and how easy they make it to adjust a colour.

Named colours

color: black;
color: rebeccapurple;   /* added in memory of Rebecca Meyer */
color: goldenrod;

There are 148 keywords — handy for quick prototyping, but too coarse for real design work.

Hexadecimal

color: #ff5733;    /* RR GG BB in base-16, each 00–FF */
color: #f00;       /* shorthand: expands to #ff0000 */
color: #ff573380;  /* 8-digit hex adds an alpha byte (80 = 50%) */

Hex is the industry default and what most design tools export. Each pair is one channel (red, green, blue) from 00 to ff.

RGB and RGBA

color: rgb(255, 87, 51);          /* legacy comma syntax */
color: rgba(255, 87, 51, 0.5);    /* fourth value is alpha, 0–1 */

/* Modern space-separated syntax — rgb() now handles alpha too */
color: rgb(255 87 51);
color: rgb(255 87 51 / 50%);

HSL and HSLA

color: hsl(9, 100%, 60%);          /* hue, saturation, lightness */
color: hsl(9 100% 60% / 50%);      /* modern syntax with alpha */

HSL is the most human format for designers, which is why it gets its own section below.

Modern formats

color: hwb(9 20% 10%);              /* hue, whiteness, blackness */
color: lch(60% 80 40);             /* perceptually uniform lightness/chroma/hue */
color: oklch(0.7 0.15 40);         /* OKLCH — great for consistent palettes */
color: color(display-p3 1 0.34 0.2); /* wider-gamut colour on capable screens */

✅ Which format when?

  • Hex: the default; matches design tools and is compact.
  • rgb() / hsl() with / alpha: whenever you need transparency.
  • HSL / OKLCH: when generating or systematically adjusting a palette.
  • Named: throwaway prototypes only.

Thinking in HSL

HSL describes a colour by three intuitive dials, which makes it easy to derive lighter, darker, or related colours by hand.

  • Hue (0–360°): position on the colour wheel — 0° red, 120° green, 240° blue.
  • Saturation (0–100%): intensity — 0% is grey, 100% is fully vivid.
  • Lightness (0–100%): 0% black, 50% the "true" colour, 100% white.
The three HSL dials Hue moves around the colour wheel from 0 to 360 degrees, saturation moves from grey to full colour, and lightness moves from black through the colour to white. Hue 0–360° red → yellow → green → cyan → blue → magenta → red Saturation 0–100% grey (0%) ————————————————→ full colour (100%) Lightness 0–100%
Figure 1 — Because HSL separates hue from lightness, you can build a whole scale by fixing the hue and stepping the lightness: hsl(210 100% 20%)hsl(210 100% 80%).

Harmonies from the wheel

SchemeRecipe (by hue)Feel
MonochromaticOne hue, vary S & LCalm, cohesive
AnalogousHues within ~30° of each otherHarmonious, natural
ComplementaryTwo hues 180° apartHigh contrast, energetic
TriadicThree hues 120° apartVibrant, balanced

📖 Colour psychology (use as a starting point, not a rule)

Blue reads as trust and calm (finance, tech); green as growth and health; red as energy and urgency; black/gold/purple as luxury. Context and culture matter, so always test with real users.

Background Properties

The simplest background is a flat fill. From there, a family of properties positions and sizes background images (which include gradients).

.panel {
  background-color: hsl(0 0% 96%);
  /* When both color and image are set, the image paints on top of the color */
  background-image: linear-gradient(to bottom, #ffffff, #f0f0f0);
}
graph TD A[background shorthand] --> B[background-color] A --> C[background-image] A --> D[background-repeat] A --> E[background-position] A --> F[background-size] A --> G[background-attachment]

The individual properties

.hero {
  background-image: url("/img/mountains.jpg");
  background-repeat: no-repeat;   /* repeat | repeat-x | repeat-y | no-repeat | space | round */
  background-position: center;    /* keywords, %, lengths, or edge offsets */
  background-size: cover;         /* cover | contain | <length> | % */
  background-attachment: fixed;   /* scroll | fixed | local — fixed gives a parallax feel */
}
Value of background-sizeBehaviourGood for
coverScale to fill the box, cropping overflowHero images, card thumbnails
containScale so the whole image fits, may leave gapsLogos, icons that must stay whole
100px 60pxExplicit width & heightDecorative patterns, UI sprites

The background shorthand

/* color image repeat attachment position / size */
.card {
  background: #333 url("/img/noise.png") no-repeat center / cover;
}

/* Multiple backgrounds stack: the FIRST layer sits on top */
.overlayed {
  background:
    linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)) no-repeat center / cover,
    url("/img/photo.jpg") no-repeat center / cover;
}

⚠️ The shorthand resets omitted values

Like the font shorthand, background snaps every property you leave out back to its initial value. If you only want to change one thing (say the position), set the specific longhand instead.

CSS Gradients

Gradients are smooth colour transitions generated by the browser — no image request, infinitely scalable, and editable in code. They are technically background images, so they live in background-image.

Linear gradients

/* Default flows top → bottom */
background-image: linear-gradient(#e66465, #9198e5);

/* Direction: keyword or angle */
background-image: linear-gradient(to right, #e66465, #9198e5);
background-image: linear-gradient(45deg, #e66465, #9198e5);

/* Colour stops with positions */
background-image: linear-gradient(to right, red 0%, gold 50%, green 100%);

/* Hard stops make crisp stripes (no blend between the two 50% points) */
background-image: linear-gradient(to right, #4f46e5 50%, #a855f7 50%);

Radial gradients

/* Radiates outward from a point; default shape is an ellipse */
background-image: radial-gradient(circle, #e66465, #9198e5);

/* Control shape, size, and origin */
background-image: radial-gradient(circle closest-side at 25% 75%, #fff, #9198e5);

Conic gradients

/* Sweeps colours AROUND a centre — perfect for pie charts and colour wheels */
background-image: conic-gradient(#4f46e5, #a855f7, #ec4899, #4f46e5);

/* A two-slice pie using hard stops */
background-image: conic-gradient(#22c55e 0deg 90deg, #e5e7eb 90deg 360deg);
Three gradient types compared Linear gradients blend along a line, radial gradients blend outward from a centre point, and conic gradients sweep colours around a centre. linear radial conic
Figure 2 — Linear blends along an axis, radial blends outward from a centre, and conic sweeps around a centre. All three accept multiple colour stops.

Repeating gradients & patterns

/* Diagonal stripes with no image file */
.stripes {
  background-image: repeating-linear-gradient(
    45deg, #606dbc, #606dbc 10px, #465298 10px, #465298 20px
  );
}

/* A dot grid using a tiny radial gradient tile */
.dots {
  background-image: radial-gradient(circle at 1px 1px, #333 1px, transparent 0);
  background-size: 12px 12px;
}

Layering & Effects

Multiple backgrounds

Comma-separate values to stack layers. A classic pattern is a dark gradient over a photo so overlaid text stays readable:

.hero {
  background:
    linear-gradient(rgba(0,0,0,0.55), rgba(0,0,0,0.55)) no-repeat center / cover,
    url("/img/city.jpg") no-repeat center / cover;
  color: #fff;
}

background-clip: text

Clip a gradient to the shape of the text for an eye-catching heading:

.gradient-text {
  background-image: linear-gradient(to right, #f06, #48f);
  background-clip: text;
  -webkit-background-clip: text;   /* Safari still needs the prefix */
  color: transparent;
  font-weight: 800;
}

background-blend-mode

/* Blend a tint into a photo without editing the image */
.duotone {
  background: url("/img/portrait.jpg") center / cover, #2563eb;
  background-blend-mode: luminosity;
}

💡 Reach for CSS before images

Gradients, patterns, and blend modes render on the GPU, add zero network requests, and scale perfectly on any screen density. Prefer them over shipping a background JPEG whenever the effect can be expressed in CSS.

Contrast & Performance

Colour contrast (WCAG)

Readable colour is not optional. The Web Content Accessibility Guidelines set minimum contrast ratios between text and its background:

TextMinimum (AA)Enhanced (AAA)
Normal body text4.5 : 17 : 1
Large text (≥ 24px, or 18.66px bold)3 : 14.5 : 1

⚠️ Don't rely on colour alone

  • Pair colour with text, icons, or patterns so colour-blind users get the message too (e.g. a red error also carries an ✕ icon).
  • Check pairs with the WebAIM Contrast Checker.
  • Over a gradient or photo background, test contrast against the lightest and darkest spots the text sits on.

Performance

  • Prefer CSS gradients to image gradients — no HTTP request, smaller payload.
  • Be cautious with large background-attachment: fixed images; they can cause scroll jank on mobile.
  • Use SVG data-URIs for crisp, tiny patterns.
  • Alpha transparency is more expensive to composite than opaque fills — use it deliberately.

Hands-on Exercise

🏋️ Build a Pure-CSS Hero

Objective: Create a hero banner whose background is entirely CSS-generated and whose heading passes contrast.

Instructions:

  1. Make a full-width <section class="hero"> at least 60vh tall containing an <h1> and a short tagline.
  2. Give it a layered background: a translucent dark linear-gradient over a colourful radial-gradient — no image files.
  3. Define your palette with HSL custom properties so you can retheme by editing one hue.
  4. Verify the heading colour hits at least 4.5 : 1 against the darkest part of the background.
  5. Bonus: add a subtle repeating-gradient dot pattern as a third layer.
💡 Hint

Layers are comma-separated in background, and the first one is on top. Put your dark overlay gradient first so it sits above the colourful base and tames it for text.

✅ Sample solution
.hero {
  --brand-h: 220;
  min-height: 60vh;
  display: grid;
  place-items: center;
  text-align: center;
  color: #fff;
  padding: 2rem;
  background:
    radial-gradient(circle at 1px 1px, rgba(255,255,255,0.15) 1px, transparent 0) 0 0 / 16px 16px,
    linear-gradient(rgba(0,0,0,0.45), rgba(0,0,0,0.55)),
    radial-gradient(circle at 30% 30%,
      hsl(var(--brand-h) 90% 55%),
      hsl(calc(var(--brand-h) + 60) 80% 40%));
}
.hero h1 { font-size: clamp(2rem, 1rem + 5vw, 4rem); }

White text over the dark overlay comfortably exceeds 4.5 : 1. Change --brand-h to reskin the whole banner.

🎯 Quick Quiz

Question 1: In rgb(255 87 51 / 50%), what does the 50% control?

Question 2: Which gradient type sweeps colours around a centre point, making it ideal for pie charts?

Question 3: What is the minimum WCAG AA contrast ratio for normal-size body text?

Summary & Quiz

🎉 Key Takeaways

  • CSS offers many colour formats: hex for defaults, rgb()/hsl() with alpha for transparency, HSL/OKLCH for building palettes.
  • HSL separates hue, saturation, and lightness so you can derive scales and harmonies by hand.
  • Backgrounds layer; the first comma-separated layer sits on top, and the shorthand resets what you omit.
  • Linear, radial, and conic gradients (plus repeating variants) replace many image files entirely.
  • Always meet WCAG contrast and never rely on colour alone to convey meaning.

📚 Further Reading

🚀 What's Next?

With colour handled, we tackle how elements are sized and spaced: The Box Model in Depth — content, padding, border, margin, and the all-important box-sizing.

🎉 Great work!

You can now paint any element and build gradients from scratch. Next: how big that element actually is.