Course outline

HTML & CSS / Maintainable presentation systems / Lesson 16

Progressive enhancement and container queries

Build a usable baseline, add supported presentation features, and adapt components to their own available space.

About 4 min readContent reviewed
On this page

Lesson goals

  • Start with a complete baseline
  • Enhance a simple list layout
  • Make compatibility assumptions reviewable

Start with a complete baseline

Progressive enhancement begins with content and interactions that already satisfy the essential task, then adds capabilities where they improve the experience. A failed stylesheet or unsupported declaration should not erase the only route to important information. This does not require every browser to look identical or support every enhancement. It requires an explicit support policy and a meaningful fallback. Native links, forms, headings, and ordinary flow provide a strong starting point. When JavaScript is needed for an advanced control, define what is available before initialization and what happens if the script never arrives or stops after partial work.

Detect features rather than brands

CSS @supports asks whether a declaration or selector syntax is supported under its defined feature-query rules. It does not prove that the resulting design is accessible, bug-free, or performant on every device. Write a safe base first and place only the enhancement inside the condition. User-agent sniffing often misidentifies browsers and ages poorly compared with capability checks. Even a supported feature can have implementation differences, so maintain a tested browser matrix for critical behavior. Use official compatibility data as planning evidence and verify the actual deployment targets rather than making a permanent claim that every modern browser supports a broad bundle of features.

Enhance a simple list layout

The first example begins with ordinary stacked articles and spacing, then enables a two-column Grid arrangement only when that declaration is supported and enough width is available. Content, headings, and order exist outside the feature query. The fallback is therefore a complete readable page rather than an empty component. Feature checks should not hide required labels or error messages. Avoid duplicating the entire content tree for the enhanced branch; presentation can usually change around one semantic structure. Test the fallback deliberately by disabling the enhancement, since a branch never exercised can drift out of alignment with the product’s actual needs.

html Feature enhancement
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Feature enhancement</title>
<style>
.collection article { margin-block: 1rem; padding: 1rem; border: 1px solid; } @supports (display: grid) { @media (min-width: 40rem) { .collection { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; } } }
</style>
</head>
<body>
<main><h1>Enhanced collection</h1><div class="collection"><article><h2>Structure</h2><p>Always readable.</p></article><article><h2>Presentation</h2><p>Columns are optional.</p></article></div></main>
</body>
</html>
Expected output
A complete stacked fallback with an optional wider grid.

The base consists of ordinary blocks. Supporting browsers may enhance the collection into columns without changing content or semantics.

Query a component’s container

A viewport media query describes the environment, while a size container query can react to an eligible ancestor’s dimensions. Establish an inline-size query container on a wrapper, then style a descendant when the wrapper is wide enough. The queried element does not ordinarily use its own size container query to style itself based on itself; choose the ancestor boundary deliberately. Inline-size containment also affects intrinsic sizing, so applying container-type to an arbitrary shrink-to-fit element can change layout. The second example keeps a stacked baseline and adds two internal columns when its named container reaches the teaching threshold.

html Container adaptation
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Container adaptation</title>
<style>
.wrapper { container-type: inline-size; container-name: card-space; max-inline-size: 50rem; } .card { padding: 1rem; border: 1px solid; } @container card-space (min-width: 30rem) { .card { display: grid; grid-template-columns: 1fr 2fr; gap: 1rem; } }
</style>
</head>
<body>
<main><h1>Container-aware card</h1><div class="wrapper"><article class="card"><h2>Workshop</h2><p>This card responds to its wrapper, not directly to the viewport.</p></article></div></main>
</body>
</html>
Expected output
The card adapts at a 30rem container width with a stacked fallback.

The wrapper establishes the named size boundary. The descendant card gains columns only when that container is wide enough; otherwise normal block flow remains.

Make compatibility assumptions reviewable

Size container queries, cascade layers, and newer selectors have distinct support histories; do not infer one from another. This course reviews official platform guidance on its stated date and uses a current Chromium fixture for representative checks, while a product must verify its own supported engines and assistive-technology combinations. Keep enhancement failure local: a card can remain stacked without preventing the rest of the page from working. Test a narrow component inside a wide page, and a wide component inside a simple shell. These cases distinguish genuine container adaptation from a viewport rule that accidentally looked correct in one screenshot.

Common errors and fixes

An unsupported feature leaves no content

Why it happens
Essential markup or visibility depended on the enhancement.
How to fix it
Restore a meaningful baseline outside the condition.
Prevent it next time
Test the disabled-enhancement path.

A card responds to the whole page instead of its slot

Why it happens
A viewport query was used for a component-local need.
How to fix it
Establish and query the intended ancestor container.
Prevent it next time
Test narrow slots inside wide pages.

Adding container-type changes intrinsic layout

Why it happens
Containment was assumed to be a passive label.
How to fix it
Review the wrapper’s sizing contract.
Prevent it next time
Measure before and after establishing containment.

Check your understanding

1. Choose a media or container query for a reusable card appearing in both a sidebar and a main column.

Show worked solution

Use a size container query when the card’s internal arrangement should depend on its allocated slot. Establish a deliberate wrapper in each context and keep a stacked fallback. A viewport query cannot distinguish a narrow sidebar from a wide main column at the same window width.

2. Why does @supports (display: grid) not prove that a particular grid interface is usable?

Show worked solution

It checks support for the declaration under feature-query rules. It does not examine content order, contrast, focus, overflow, or the application task. Keep behavioral and accessibility testing separate from syntax support detection, and verify the complete design on supported environments.

Key takeaways

  • Enhancements should improve an already usable baseline.
  • Feature support is narrower than behavioral correctness.
  • A container boundary has sizing consequences.

Official references