Code of the Day
BeginnerStyling with CSS

Colors, Typography, and Units

CSS units and color formats each have trade-offs — choosing the right one depends on whether you want absolute or relative sizing.

Web FoundationsBeginner8 min read
Recommended first
By the end of this lesson you will be able to:
  • Write colors using hex, rgb(), and hsl() notations
  • Distinguish between absolute units (px) and relative units (em, rem, %)
  • Set font properties — font-family, font-size, font-weight, line-height
  • Explain when to use rem vs em for font sizing

CSS lets you express colours in multiple formats and sizes in multiple units. The variety is not arbitrary — each format has a distinct mental model that makes certain tasks easier or harder. Knowing which tool to reach for produces cleaner stylesheets and fewer "why is this element the wrong size?" moments.

Colour formats

Hex

The most common format. A # followed by six hexadecimal digits encoding red, green, and blue as pairs:

color: #3a7bd5;       /* red=0x3a, green=0x7b, blue=0xd5 */
background: #ffffff;  /* white */
background: #000000;  /* black */

A three-digit shorthand works when each pair is a repeated digit: #aabbcc#abc. Hex is precise and copy-pasteable from design tools, but adjusting "make this 10% lighter" requires converting to a different format.

rgb()

Expresses each channel as a decimal 0–255:

color: rgb(58, 123, 213);    /* same blue as above */
color: rgb(255, 255, 255);   /* white */

rgba() adds an alpha (opacity) channel from 0.0 (transparent) to 1.0 (fully opaque):

background: rgba(0, 0, 0, 0.5);   /* 50% transparent black overlay */

Modern CSS lets you write rgb(58 123 213 / 0.5) without commas — both syntaxes work.

hsl()

Hue, Saturation, Lightness — the format most intuitive for designers and the easiest to adjust by feel:

color: hsl(218, 63%, 54%);   /* same blue again */
  • Hue — the colour wheel position, 0–360 degrees. 0 = red, 120 = green, 240 = blue.
  • Saturation — how vivid the colour is. 0% is grey; 100% is fully vivid.
  • Lightness — how light or dark. 0% is black; 100% is white; 50% is the pure colour.

To create a lighter variant of a colour, increase lightness. To mute it, reduce saturation. This is much harder to do intuitively with hex. Many design systems define a colour as an HSL base and then generate a scale by varying lightness.

hsl() also accepts an optional alpha: hsl(218 63% 54% / 0.7).

All three formats — hex, rgb(), and hsl() — describe exactly the same colour space and can represent any of the same colours. Pick based on how you will be working with the colour: hex from a design file, hsl when you want to derive tints and shades in code.

Units

Absolute: px

A CSS pixel is a fixed unit. 16px is 16 pixels regardless of context:

border-width: 2px;
border-radius: 4px;

Pixels are predictable and appropriate for things that should not scale with text size: borders, shadows, fine details. They are a poor choice for font sizes because they ignore the user's browser preference. A user who has set their browser's default text size to 20px (for readability) will have that preference overridden by font-size: 16px.

Relative: em

1em is equal to the font-size of the current element. If an element has font-size: 20px, then 1em = 20px for that element:

.card {
  font-size: 18px;
  padding: 1em;   /* 18px — matches the font size */
}

em scales with the element's own font size, which is useful for padding and spacing that should grow with the text. The trap: if elements are nested, each level multiplies the parent's font size:

.outer { font-size: 1.2em; }   /* 1.2 × browser default */
.inner { font-size: 1.2em; }   /* 1.2 × 1.2 × browser default = 1.44× */

The compounding effect makes em hard to manage for font sizes in nested components.

Relative: rem

1rem is always equal to the font-size of the root element (<html>), not the current element. It does not compound:

html { font-size: 16px; }   /* browser default — usually don't set this */

h1 { font-size: 2rem; }     /* always 32px, regardless of nesting */
p  { font-size: 1rem; }     /* always 16px */

Because rem roots itself at the <html> element's size, it respects the user's browser font size preference. If the user sets their browser to 20px default, 1rem = 20px and everything scales proportionally. Use rem for font sizes and most spacing.

Relative: %

Percentage is relative to the parent element's corresponding property:

.container {
  width: 80%;   /* 80% of parent's width */
}

p {
  font-size: 90%;   /* 90% of parent's font-size — use rem instead */
}

Percentages are most useful for widths and layout (width: 100% to fill the parent), and less useful for font sizes where rem is clearer.

Typography properties

p {
  font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: 0.01em;
}

font-family

A comma-separated list of fonts — the browser uses the first available. Always end with a generic family (serif, sans-serif, monospace) as a final fallback. Quote names that contain spaces: 'Times New Roman'.

font-size

Set in rem for body text. The browser default is typically 16px.

font-weight

Use numeric values for precision: 100 (thin) through 900 (black), in increments of 100. 400 is normal; 700 is bold. Named keywords (bold, normal) also work.

line-height

Controls the vertical space between lines of text. Use a unitless number like 1.6 rather than a pixel value — it multiplies by the element's own font size and stays proportional if the font size changes. A common range is 1.4 for headings to 1.7 for body text.

line-height: 1.5 means each line of text gets 150% of the font size as its allotted vertical space. Unitless values are inherited as the multiplier, not a computed pixel value — which is why they are preferred over line-height: 24px.

letter-spacing

Fine-tunes the space between characters. Common uses: uppercase headings often benefit from letter-spacing: 0.05em to 0.1em; body text rarely needs adjustment. Use em so the spacing scales with the font size.

Where to go next

Next: Lab — Style a Page — apply everything you have learned in the Styling with CSS module by taking a semantic HTML document and writing a full stylesheet from scratch.

Finished reading? Mark it complete to track your progress.

On this page