web · Level 2

CSS: responsive layouts, grids and typography

Style the event page by hand so it reads well on a phone and a laptop, measure each result in a real browser, and learn to check CSS an AI assistant writes.

By Mickarle Wagstaff-Irons - Micky Irons

  • Level 2Getting going
  • 140 min
  • 6 chapters
  • Online course and PDF workbook
The Pageweb / 02

Read, practise and review

Your next step

Start this course online

Register your start, then work through the lessons and exercises at your own pace. You can download the PDF separately. Where a scored exam is available, you will find it after the lessons.

Register or resume your course

Mickai privately records this registration and sends its team a course-start notification. It records your intention to start, not proof of attendance or completion. Our course-start privacy notice explains the details and the 30-day resume cookie.

Follow the Mickai company page on LinkedIn

You can start learning without subscribing or following. Newsletter email confirmation and provider enrolment are recorded separately.

Start with the essentials

The short answer

Responsive CSS starts with a border-box model, custom properties for your choices, and layouts that adapt by themselves: flexbox for a line of items, grid for columns, and fluid type from clamp(). Add media or container queries only where needed, honour the reader's colour scheme, motion and text size, and keep a visible focus ring. Test at several widths, and check AI-written CSS the same way.

What you will learn

  • You will be able to explain the box model and box-sizing, and measure a box in the browser.
  • You will be able to predict which rule wins from the cascade order and specificity, and keep colours and spacing in custom properties.
  • You will be able to build a flexbox row and a grid that chooses its own column count, and read its tracks in developer tools.
  • You will be able to make type and layout adapt with clamp(), media queries, container queries and logical properties, and say how well each is supported.
  • You will be able to honour colour scheme, reduced motion, focus visibility and contrast, naming the WCAG 2.2 criteria correctly.
  • You will be able to review CSS that an AI assistant wrote and find its common faults by measuring.

Who it is for

People who have built the event page in the HTML workbook and want it to look good on a phone and a laptop, writing CSS by hand without a framework. You should be able to edit files in a plain text editor and open them in a browser.

Before you start

  • The HTML workbook (build a meaningful, accessible page), or the finished Marigold Lane event page from it. A plain text editor and a desktop browser with developer tools. The tool names here are those of Microsoft Edge, and other browsers differ in detail. No JavaScript knowledge is needed: the few one-line Console checks are given in full.

Learn in your browser · Chapter 01 of 06

01

Every element is a box

Measure the boxes on the event page, and see why one line of CSS makes widths mean what they say.

This workbook continues the Marigold Lane Seed Swap page from the HTML workbook. Leave its style.css alone and add a second file, layout.css, that loads after it. Every result was measured in Microsoft Edge 153 at three viewport widths: 360, 768 and 1280 CSS pixels (the browser's unit of length, not a screen dot).

Create an empty layout.css in event-page, and add this line to index.html under the existing link line.

html · 1 line
<link rel="stylesheet" href="layout.css">

Every element makes a box: content, padding, border and margin, from the inside out. By default (box-sizing: content-box) width sets the content only, and padding and border are added outside it. With border-box, width covers content, padding and border (MDN). The HTML workbook's style.css gives main a max-width of 42rem (a rem is the root font size, commonly 16 pixels, so 672) and 1rem of padding left and right.

Open index.html, right-click, choose Inspect and press Ctrl+Shift+J (Command+Option+J on macOS) for the Console. The first time you paste there, Edge asks you to type allow pasting: do so only for code you understand, like these read-only lines (Microsoft). This line returns the border box width in CSS pixels (MDN). For other widths use Device Emulation: Toggle device emulation on the Activity Bar, Responsive Viewport Mode, then type a width. Microsoft calls it a first-order approximation of a phone.

js · 1 line
document.querySelector('main').getBoundingClientRect().width

At 768 and 1280 the max-width limits only the content, so the padding makes the box 704 wide. Add this to layout.css, then measure again.

css · 1 line
*, *::before, *::after { box-sizing: border-box; }

* matches every element, ::before and ::after generated content. In a normal window or with the Desktop device type, a classic scrollbar takes a few pixels, so some of your figures may be lower.

Try it yourself · Activity 01

15 min

Measure a box

Measure main before and after the box-sizing rule.

  1. Add the link line. At 360, 768 and 1280 run the getBoundingClientRect line and also getComputedStyle(document.querySelector('main')).width.
  2. Add the box-sizing rule, reload and repeat.

Which number changed at 360, and which did not?

Worked answer

Before: bounding widths 360, 704 and 704, and computed width 328px, 672px and 672px, because in the default model it reports the content alone. After: 360, 672 and 672, and 360px, 672px and 672px. At 360 the bounding width never changes, because main fills the screen either way. If nothing changes, check that layout.css sits beside index.html, is not named layout.css.txt, and is linked after style.css.

Next chapter

Learn in your browser · Chapter 02 of 06

02

The cascade, specificity and custom properties

When rules disagree the browser must pick one. Learn the real order, and keep your choices in custom properties.

The cascade picks one winning declaration for each property on each element. The CSS Cascading specification sorts the candidates by these criteria, highest first, plus two not used here: shadow DOM context and @layer.

Scroll sideways to see every column.

The cascade, specificity and custom properties · Table 1
CriterionIn practice
Origin and importanceYour styles beat the browser's. !important beats normal.
Element-attached stylesA style attribute beats a rule.
SpecificityThe more specific selector wins.
Order of appearanceThe last wins. Linked sheets join in order.

So layout.css, linked second, wins ties with style.css. Specificity is a three-part score: A counts ID selectors, B classes, attributes and pseudo-classes, C element names and pseudo-elements. * and combinators count nothing. Scores compare from A onwards, never as one number, so one ID beats any number of classes. :is(), :not() and :has() take the score of their most specific argument, and :where() counts zero (Selectors Level 4). Hover a selector in the DevTools Styles pane to see its score (Microsoft).

Custom properties (CSS variables) are names that begin with two hyphens. Declare them once, usually on :root, read them with var(), and override them on any element. Add this to layout.css.

css · 10 lines
:root {
  --ink: #1b1a17;
  --paper: #fbf7ec;
  --accent: #6b4f00;
  --page: 56rem;
  --gutter: 1rem;
}
body { color: var(--ink); background: var(--paper); }
a { color: var(--accent); }
header, main, footer { max-width: var(--page); padding-inline: var(--gutter); }

The colours are style.css's own, so nothing changes visibly, but the last rule swaps its 42rem limit for 56rem: main now measures 360, 768 and 896. var() works only in property values, not in a media or container query condition (MDN, CSS Variables specification): @media (min-width: var(--bp)) never matched in the test.

Try it yourself · Activity 02

15 min

Specificity ladder

Predict the colour of the first About list item after each step, then check it with getComputedStyle(document.querySelector('#about li')).color.

  1. Add li { color: green; } and main ul li { color: orange; } to layout.css.
  2. Add #about li { color: brown; }, then move it to the top of the file.
  3. Change li { color: green; } to li { color: green !important; }, then delete the test rules.

Which step shows that specificity is not one number?

Worked answer

Step 1: orange, rgb(255, 165, 0): main ul li scores 0,0,3 against 0,0,1. Step 2: brown, rgb(165, 42, 42), before and after the move: #about li scores 1,0,1, so one ID beats three element names, and order matters only on a tie. Step 3: green, rgb(0, 128, 0): !important outranks normal declarations.

Next chapter

Learn in your browser · Chapter 03 of 06

03

Flexbox and grid

Flexbox lays items along one line, grid along rows and columns. Use each where it fits.

Flexbox is one-dimensional: items run along the main axis, a row or a column, and the cross axis runs across it. justify-content spaces items along the main axis, align-items aligns them across it, and flex-wrap: wrap lets items drop to a new line (MDN). This makes the header a row, brand left and menu right, wrapping when it must. gap sets the space between items and lines.

css · 7 lines
header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
}

Grid is two-dimensional: you define tracks (columns and rows) and items fall into them, and fr is a share of the free space. Add a Stalls section to index.html between the programme and sign-up sections, then the grid rules.

html · 9 lines
    <section id="stalls">
      <h2>Stalls</h2>
      <ul class="cards">
        <li><article class="stall"><h3>Vegetable seeds</h3><p>Beans and peas.</p></article></li>
        <li><article class="stall"><h3>Flower seeds</h3><p>Sweet peas.</p></article></li>
        <li><article class="stall"><h3>Cuttings</h3><p>Mint, in damp paper.</p></article></li>
        <li><article class="stall"><h3>Tea and cake</h3><p>Sold for the hall.</p></article></li>
      </ul>
    </section>

css · 12 lines
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
  gap: 1rem;
  padding: 0;
  list-style: none;
}
.stall {
  padding: 1rem;
  border: 1px solid var(--ink);
  border-inline-start: 6px solid var(--accent);
}

Read the columns line from the inside out. minmax(12rem, 1fr): each column at least 12rem, at most one share. repeat(auto-fit, ...): as many columns as fit. min(12rem, 100%) stops overflow in a container narrower than 12rem. With few items auto-fit collapses empty columns so items stretch, and auto-fill keeps them (MDN, CSS Grid Level 2).

Use flexbox when content decides the flow along one line, grid when you decide the columns. In DevTools, click the grid badge in the DOM tree for an overlay, and tick Show track sizes in the Layout tab (Microsoft).

Try it yourself · Activity 03

20 min

Header and stalls at three widths

Add all three pieces, then look at 360, 768 and 1280.

  1. At each width note whether the menu sits beside the brand, and read getComputedStyle(document.querySelector('.cards')).gridTemplateColumns: the pixel track sizes, one per column.
  2. At 1280 add .cards > li:nth-child(n+3) { display: none; }, reload and read the tracks. Change auto-fit to auto-fill and read them again. Then undo both changes.

Which keyword suits a row of stall cards, and why?

Worked answer

The menu wraps below the brand at 360 and sits beside it at 768 and 1280. You see a stack of four cards, then three and one, then a row of four. The tracks are 328px, 234.656px 234.672px 234.672px and 204px 204px 204px 204px. With two cards showing at 1280, auto-fit gives 424px 424px 0px 0px (the cards stretch, the empty tracks collapse) and auto-fill gives 204px 204px 204px 204px (the cards keep their width). Either keyword is right if you can say why.

Next chapter

Learn in your browser · Chapter 04 of 06

04

Fluid type, media queries and container queries

Adapt the page without piles of breakpoints: text that scales, one media query, and a container query.

Fluid type grows with the screen between limits: clamp(min, preferred, max) never returns less than min or more than max. Give the preferred value a rem part so the reader's text size still counts: vw (1% of the viewport width) alone ignores it, and WCAG failure F94 says text sized mainly in viewport units is likely to fail 1.4.4 Resize Text. MDN advises a maximum at least twice the minimum.

css · 1 line
h1 { font-size: clamp(1.5rem, 1.1rem + 2.5vw, 3rem); line-height: 1.2; }

At 360 the preferred value is 1.1 x 16 + 0.025 x 360 = 26.6 pixels, between the limits, so that is the size.

Media queries apply rules by viewport features. Write them mobile first with min-width and in rem: relative units in a media query come from the initial font size, not page styling (Media Queries specification), so 40rem is 640 pixels at the default text size even with html { font-size: 200% }. Here the query changes a token, not the rules.

css · 4 lines
p { max-inline-size: 65ch; }
@media (min-width: 40rem) {
  :root { --gutter: 2rem; }
}

Container queries style a component by its container's width, not the screen's. Mark the container with container-type: inline-size and use @container on its descendants: an element cannot be styled by its own container query. A stall card's cell width changes with the grid, so the card is wide on the phone and narrow on the laptop: a viewport query gets that backwards.

css · 4 lines
.cards > li { container-type: inline-size; }
@container (min-width: 16rem) {
  .stall { display: grid; grid-template-columns: 6rem 1fr; gap: 1rem; }
}

On the phone each card shows its title beside its text. On the tablet and laptop the title sits above it.

Support. Size container queries are in the CSS Containment Module Level 3, still a W3C Working Draft (August 2022). Browsers ship them: on 26 September 2026 caniuse listed Edge and Chrome 106, Firefox 110 and Safari 16.0 onwards, and marked them Baseline widely available. Older browsers need a fallback (MDN).

Logical properties name sides by writing direction, not left and right: in English inline runs left to right and block top to bottom, and in Arabic inline is reversed (MDN). This page uses padding-inline, max-inline-size and border-inline-start, and margin-left would become margin-inline-start. 65ch is 65 zeros wide.

Try it yourself · Activity 04

20 min

Predict, then flip

Add this chapter's rules to layout.css, then predict and measure.

  1. Work out the preferred h1 value at 360, 768 and 1280 by hand (1.1rem is 17.6 pixels), apply the limits, then read getComputedStyle(document.querySelector('h1')).fontSize.
  2. At each width read the display of .stall and the paddingLeft of main.
  3. At 1280 read borderLeftWidth and borderRightWidth of .stall. Run document.documentElement.dir = 'rtl', read them again, then reload.

Why does the card switch layout at 360 but not at 768, when 768 is the wider screen?

Worked answer

The preferred values are 26.6, 36.8 and 49.6, so fontSize reads 26.6px, 36.8px and 48px. .stall is grid, block and block: the cells are 328, 224 and 196 pixels wide against a 16rem (256 pixel) threshold. The padding of main is 16px, 32px, 32px. The borders read 6px and 1px, then 1px and 6px after the flip. A cell is widest in a one-column grid, which is on the phone, so the card follows its cell, not the screen.

Next chapter

Learn in your browser · Chapter 05 of 06

05

Preferences, focus and contrast

Readers choose a colour scheme and a motion level, and many use only a keyboard. Style for them, then check.

Colour scheme. prefers-color-scheme reports whether the reader asked for a light or dark theme. Because your colours are tokens, a dark theme is one rule. color-scheme: light dark also restyles form controls, scrollbars and the page canvas (MDN).

css · 4 lines
:root { color-scheme: light dark; }
@media (prefers-color-scheme: dark) {
  :root { --ink: #fbf7ec; --paper: #1b1a17; --accent: #e3b94d; }
}

To test without changing your system, use the Toggle common rendering emulations button in the Styles tab (Microsoft). Text is 16.26:1 and links 9.37:1 on the dark background.

A trap. Press Tab in dark mode. style.css draws the focus ring in a fixed #1b1a17, 1.00:1 against the dark background, so it vanishes, and so do the table borders. A colour fixed in one place breaks when tokens change in another. :focus-visible shows focus when the browser judges it should be evident, typically for keyboard use (MDN).

css · 2 lines
:focus-visible { outline-color: var(--ink); }
th, td { border-color: var(--ink); }

The ring is now rgb(251, 247, 236) in dark mode and rgb(27, 26, 23) in light, 16.26:1 either way. WCAG wants visible focus (2.4.7 Focus Visible, AA), a 3:1 indicator against adjacent colours (1.4.11 Non-text Contrast, AA) and author-created content, such as a sticky header, that does not entirely hide the focused control (2.4.11 Focus Not Obscured (Minimum), AA, new in 2.2; WCAG technique C43 uses scroll-padding). 2.4.13 Focus Appearance is new but AAA. Removing the indicator is failure F78.

Motion. prefers-reduced-motion: reduce reports a request for less non-essential motion, which can trigger discomfort in people with vestibular disorders (MDN). Windows 11 has it under Accessibility, Visual effects, Animation effects. Add motion only when the reader has not asked for less.

css · 4 lines
@media (prefers-reduced-motion: no-preference) {
  .stall { transition: transform 0.2s ease-out; }
  .stall:hover { transform: translateY(-4px); }
}

The card's transitionDuration was 0.2s with no preference and 0s with reduce (emulated). This supports 2.3.3 Animation from Interactions (AAA); technique C39 uses the query.

Contrast. WCAG 1.4.3 Contrast (Minimum) (AA) asks for 4.5:1 for normal text and 3:1 for large text. The page's light links are 7.15:1. Ratios are not rounded, so 2.999:1 fails 3:1 (1.4.11 guidance).

Try it yourself · Activity 05

20 min

Dark, focus and motion

Add the three rule groups in order and test each one.

  1. Add the dark-scheme rules. In DevTools choose prefers-color-scheme: dark, click the page background near the top and press Tab. Can you see the ring?
  2. Add the focus rules, reload, click near the top and press Tab again, then read getComputedStyle(document.activeElement).outlineColor.
  3. Add the motion rules. Read getComputedStyle(document.querySelector('.stall')).transitionDuration, turn on your system's reduced motion setting, reload and read it again.

Why did one hard-coded colour matter only after you added a dark theme?

Worked answer

Before the fix the ring is rgb(27, 26, 23) on rgb(27, 26, 23), 1.00:1, so you see no ring. After it the colour is rgb(251, 247, 236). The duration is 0.2s, then 0s with reduced motion on (emulated in the test run). The fixed colour only worked while the background never changed.

Next chapter

Learn in your browser · Chapter 06 of 06

06

Debugging layout, and reviewing AI-written CSS

Learn the browser's tools, then use them on a stylesheet you did not write.

Scroll sideways to see every column.

Debugging layout, and reviewing AI-written CSS · Table 2
SymptomTool in Edge DevTools
A rule has no effectStyles tab: all matching rules, overridden ones too, and CSS issues. Computed tab: what applies.
A box is the wrong sizeThe box model diagram in the Styles pane.
A container query does nothingThe inline-size badge marks the container.
It breaks on a phoneDevice Emulation. Show media queries marks breakpoints.

Sideways overflow is the commonest phone bug. At 360, this Console line lists the elements whose right edge passes the viewport, outermost first, and changes nothing. On the finished page it returned an empty list at 320, 360, 768 and 1280.

js · 1 line
[...document.querySelectorAll('body *')].filter(e => e.getBoundingClientRect().right > document.documentElement.clientWidth).map(e => e.tagName.toLowerCase())

AI-written CSS. An assistant can write a plausible stylesheet in seconds, but its faults are predictable: properties that do not exist, fixed pixel widths and heights, !important to win arguments, prefixes for long-supported features (caniuse lists box-shadow and border-radius as Baseline widely available), removed focus outlines and pale greys. This stylesheet was written for this workbook, not by any product. Copy event-page to event-page-review, save it as assistant.css there and link it instead of layout.css.

css · 6 lines
main { width: 1200px; max-width: none; margin: 0 auto; }
h1 { font-size: 4vw; }
.cards li { float: left; width: 300px; height: 90px; overflow: hidden; margin-x: 1rem; }
nav a { -webkit-box-shadow: 0 2px 4px #000; -moz-border-radius: 6px; color: #999999 !important; }
* { outline: none !important; }
body { overflow-x: hidden; }

A checker sees what is not allowed, and can be wrong: the Nu Html Checker (26.9.16) reported the valid container-type and @container in the finished layout.css as two errors. The checker receives whatever you upload, so send only practice files. Know your limits: none of this is WCAG conformance, and these numbers come from one browser on one machine, so test on real phones, in other browsers and with a screen reader.

Try it yourself · Activity 06

25 min

Review the stylesheet

Review assistant.css as you would a page from a stranger. List at least six problems, with a one-line fix for each.

  1. Build event-page-review. At 360 wide run the overflow line, try scrolling sideways, click the page background, press Tab, and inspect the first nav a.
  2. Upload assistant.css to the Nu Html Checker (file upload) and run CSS.supports('margin-x', '1rem').
  3. Write your list, apply your fixes and measure again at 360, 768 and 1280.

Which fault would be hardest to spot behind a confident explanation?

Worked answer

Findings: the overflow line starts main, h1, p at 360 and 768 and is empty at 1280. Scrolling sideways does nothing. The h1 is 14.4px, 30.72px and 51.2px. The first Tab stop has outline 3px none. #999999 is 2.66:1 on the cream page. The checker reports one error, at line 3: margin-x: Property margin-x doesn't exist. CSS.supports is false for margin-x and -moz-border-radius but true for -webkit-box-shadow, an alias. Fixes: (1) delete width: 1200px, as style.css already limits main; (2) delete overflow-x: hidden, which cuts the overflow off; (3) clamp() with a rem part, not 4vw; (4) no fixed card width, height or overflow: hidden, since text clipped when a reader widens text spacing is WCAG failure F104: let cards wrap; (5) margin-inline, not margin-x; (6) drop the prefixes; (7) drop #999999 !important; (8) delete outline: none !important (failure F78). My tested fix replaced the file with the chapter 4 h1 rule, .cards { display: flex; flex-wrap: wrap; gap: 1rem; padding: 0; list-style: none; }, .cards li { flex: 1 1 12rem; } and nav a { box-shadow: 0 2px 4px #000; border-radius: 6px; }. The overflow line was then empty at all three widths, h1 measured 26.6px, 36.8px and 48px, and Tab showed a 3px solid ring.

Assessment options

Keep learning

The complete workbook

This workbook teaches CSS by hand, with no frameworks. You will extend a small invented event page with a box-model fix, custom properties, a flexbox header, a responsive grid of cards, fluid headings, a container query, a dark theme and reduced-motion and focus styles, measuring every result in a real browser at three widths. You will also learn to debug layout in developer tools and to review CSS written by an AI assistant.

  1. 01
    Every element is a box

    Measure the boxes on the event page, and see why one line of CSS makes widths mean what they say.

    Read here · 1 exercise
  2. 02
    The cascade, specificity and custom properties

    When rules disagree the browser must pick one. Learn the real order, and keep your choices in custom properties.

    Read here · 1 exercise
  3. 03
    Flexbox and grid

    Flexbox lays items along one line, grid along rows and columns. Use each where it fits.

    Read here · 1 exercise
  4. 04
    Fluid type, media queries and container queries

    Adapt the page without piles of breakpoints: text that scales, one media query, and a container query.

    Read here · 1 exercise
  5. 05
    Preferences, focus and contrast

    Readers choose a colour scheme and a motion level, and many use only a keyboard. Style for them, then check.

    Read here · 1 exercise
  6. 06
    Debugging layout, and reviewing AI-written CSS

    Learn the browser's tools, then use them on a stylesheet you did not write.

    Read here · 1 exercise

Also inside: a 10-point checklist, a glossary of 11 terms and 10 questions and answers to test yourself. 6 hands-on exercises, each with a worked answer at the back where the workbook gives one.

The PDF is free. We ask for your name and email before downloading. Read the privacy notice at the download form. Free to download and use for personal learning, study groups and inside your own team. Please do not resell the workbooks or republish them as your own. Link people to trust-agent.ai instead.

Get your free PDF workbook

Enter your name and email, then download the complete workbook. This form also works without JavaScript.

We privately record your name, email and request IP for this download. Read our privacy notice and retention policy.

Visit Mickai on LinkedIn

Newsletter confirmation does not affect your download. Following Mickai on LinkedIn is optional; this site does not verify followers.

Test yourself

Questions and answers

Why do I need box-sizing: border-box?

By default width sets only the content, and padding and border are added outside it, so a box is wider than the number you wrote. With border-box, width covers content, padding and border. In this workbook's test at 768 and 1280 pixels, the event page's main measured 704 pixels wide by default and 672 with it.

What is the difference between flexbox and grid?

Flexbox is one-dimensional: it arranges items along a row or a column and can wrap them. Grid is two-dimensional: you define columns and rows and place items in them. Use flexbox when the content decides the flow along one line, and grid when you want to decide the columns.

What does repeat(auto-fit, minmax(12rem, 1fr)) do?

It creates as many columns as fit, each at least 12rem wide and sharing any spare space equally. auto-fit collapses empty columns so few items stretch to fill the row, and auto-fill keeps them. Write min(12rem, 100%) for the minimum so a container narrower than 12rem cannot overflow.

Why is my CSS rule being ignored?

Usually another rule wins. Inspect the element: the Styles tab lists every matching rule with overridden ones marked, and hovering a selector shows its specificity. A higher-specificity selector beats a later one, and a later one beats an earlier one of equal score. A misspelt property is rejected by the browser.

Is !important always wrong?

It is a blunt tool. It outranks normal declarations whatever the selector, so overriding it needs another !important that wins on specificity or order, and stylesheets get harder to change. Fix the specificity or the order instead. An AI assistant that scatters it through a stylesheet is showing a warning sign.

Should I use media queries or container queries?

Use a media query when the page as a whole should change with the screen or a reader setting, such as colour scheme. Use a container query when a component should adapt to the space it is given, wherever it is placed. A card in a narrow column and in a wide one can then share one rule.

Can I use container queries yet?

Size container queries are widely supported. On 26 September 2026 caniuse listed them in Edge and Chrome 106 and later, Firefox 110 and later and Safari 16.0 and later, and marked them Baseline widely available. The W3C specification is still a Working Draft. Check the support tables again on the day you use them.

How do I make text scale with the screen and still respect zoom?

Use clamp(min, preferred, max) with a rem part in the preferred value, such as clamp(1.5rem, 1.1rem + 2.5vw, 3rem). A size in vw alone ignores the reader's text size setting, which WCAG's failure technique F94 warns against. MDN advises a maximum at least twice the minimum.

Do I still need vendor prefixes like -webkit-?

Rarely. Caniuse lists box-shadow and border-radius as Baseline widely available, so prefixed copies add nothing, and -moz-border-radius was rejected by Edge 153 in this workbook's test. Check a property's support table before adding any prefix, because a few prefixed forms still matter.

How do I check CSS an AI assistant wrote?

Treat it as a draft from a stranger. Run it through the Nu Html Checker, which caught the invented margin-x in this workbook's test but also reported valid container queries as errors. Then look for what it misses: fixed pixel widths, !important, prefixes, removed focus outlines and low contrast. Test at 360, 768 and 1280 pixels, find any overflow, press Tab, and try dark mode and reduced motion.

Write as you go

My notes

Use this scratchpad for your own notes, working or answers as you read. Notes are saved in this browser on this device. Downloading makes a local copy; it does not send your notes to Mickai.

Consolidate your learning

Review your work

Work through the exercises and questions, then compare your reasoning with the worked answers. A scored exam and verifiable certificate are not yet available for this course.

Review the questions

Learn the language

Key terms

CSS pixel
The browser's unit of length, px. It is a CSS unit, not a physical screen dot.
Box model
How every element becomes a box of content, padding, border and margin, from the inside out.
Cascade
The rules by which the browser picks one winning declaration when several apply: origin and importance, then specificity, then order.
Specificity
A three-part score for a selector (IDs, then classes and attributes, then element names). Higher parts win first.
Custom property
A name starting with two hyphens, such as --accent, that holds a value you reuse with var().
Flexbox
A one-dimensional layout model that arranges items along a row or a column and can wrap them onto new lines.

6 of the workbook's 11 terms. The complete glossary is in the workbook.

Follow the evidence

Sources and checks

Facts last checked: .

Examples in this workbook were run on: Microsoft Edge 153.0.4234.48 (system install, headless) driven by Playwright 1.59.0 for Python 3.12.10 on Windows 11 Pro, at viewport widths of 320, 360, 768 and 1280 CSS pixels (no classic scrollbar; a classic one made the page area 15 pixels narrower); CSS checked with the W3C Nu Html Checker online service (checker version 26.9.16), through its file upload form and its JSON interface; caniuse support data read through caniuse.com on 2026-09-26 (2026-09-26).

These workbooks use AI assistance. See how the workbooks are made.

  1. CSS Cascading and Inheritance Level 5W3C
  2. Selectors Level 4W3C
  3. CSS Box Sizing Module Level 3W3C
  4. CSS Flexible Box Layout Module Level 1W3C
  5. CSS Grid Layout Module Level 2W3C
  6. CSS Values and Units Module Level 4W3C
  7. Media Queries Level 4W3C
  8. CSS Containment Module Level 3W3C
  9. CSS Custom Properties for Cascading Variables Module Level 1W3C
  10. Web Content Accessibility Guidelines (WCAG) 2.2W3C
  11. Understanding Success Criterion 1.4.4: Resize TextW3C Web Accessibility Initiative
  12. Understanding Success Criterion 1.4.11: Non-text ContrastW3C Web Accessibility Initiative
  13. Understanding Success Criterion 1.4.12: Text SpacingW3C Web Accessibility Initiative
  14. Understanding Success Criterion 2.4.7: Focus VisibleW3C Web Accessibility Initiative
  15. Understanding Success Criterion 2.4.11: Focus Not Obscured (Minimum)W3C Web Accessibility Initiative
  16. Understanding Success Criterion 2.3.3: Animation from InteractionsW3C Web Accessibility Initiative
  17. F94: Failure of Success Criterion 1.4.4 due to incorrect use of viewport units to resize textW3C Web Accessibility Initiative
  18. F78: Failure of Success Criterion 1.4.11, 2.4.7 and 2.4.13 due to styling element outlines and bordersW3C Web Accessibility Initiative
  19. C39: Using the CSS prefers-reduced-motion query to prevent motionW3C Web Accessibility Initiative
  20. C43: Using CSS scroll-padding to un-obscure contentW3C Web Accessibility Initiative
  21. The box modelMDN Web Docs
  22. box-sizingMDN Web Docs
  23. Using CSS custom properties (variables)MDN Web Docs
  24. Basic concepts of flexboxMDN Web Docs
  25. Basic concepts of grid layoutMDN Web Docs
  26. repeat()MDN Web Docs
  27. clamp()MDN Web Docs
  28. Using media queriesMDN Web Docs
  29. CSS container queriesMDN Web Docs
  30. CSS logical properties and valuesMDN Web Docs
  31. prefers-reduced-motionMDN Web Docs
  32. prefers-color-schemeMDN Web Docs
  33. color-schemeMDN Web Docs
  34. :focus-visibleMDN Web Docs
  35. Element: getBoundingClientRect() methodMDN Web Docs
  36. Window: getComputedStyle() methodMDN Web Docs
  37. <length> CSS type (including the rem unit)MDN Web Docs
  38. CSS features reference (DevTools)Microsoft Learn, Microsoft Edge developer documentation
  39. Inspect CSS Grid layoutsMicrosoft Learn, Microsoft Edge developer documentation
  40. Inspect and debug CSS container queriesMicrosoft Learn, Microsoft Edge developer documentation
  41. Emulate mobile devices (Device Emulation)Microsoft Learn, Microsoft Edge developer documentation
  42. Console overviewMicrosoft Learn, Microsoft Edge developer documentation
  43. Run JavaScript in the Console (Allow pasting into the Console)Microsoft Learn, Microsoft Edge developer documentation
  44. CSS Container Queries (Size), support table read on 2026-09-26caniuse
  45. CSS3 Box-shadow, support table read on 2026-09-26caniuse
  46. CSS3 Border-radius, support table read on 2026-09-26caniuse
  47. Nu Html Checker (web service)W3C

Created by Mickarle Wagstaff-Irons - Micky Irons with the Mickai team. Published by Mickai LTD. Last updated 26 September 2026.

NextKeep going

Where to go next