# How do you diagnose scroll regressions after adding CSS container queries?

> Diagnose scroll regressions after adding container queries, then test narrower query boundaries, containment, and offscreen rendering with browser traces.

Canonical URL: https://www.devobs.io/articles/qa-ge50-css-containment-container-query-regressions/
By: Nina Patel
Published: 2024-10-02T18:04:13.453Z
Updated: 2026-09-06T10:18:15.722Z
Section: Architecture

Adding container queries can introduce size-dependent style relationships, but the timing of a regression does not establish its cause. Capture a scroll trace to distinguish style recalculation, layout, paint, and script costs. If changing container dimensions drive the expensive work, test a narrower query boundary. Apply stronger containment or offscreen skipping only where the component’s sizing and rendering requirements allow it.

## What changed when you added container queries?

Container queries are not inherently slow, but they change what the browser must track. A size query only works after you establish a containment context with `container-type`, and `inline-size` or `size` also applies containment effects to that element, as documented in [MDN’s container queries guide](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries). That means a component’s final styles may now depend on an ancestor’s measured size rather than only the viewport or the component’s own local rules.

One hypothesis to test is that a changing ancestor became the query container for many descendants. A scrolling column, dashboard shell, or virtualized list wrapper can become a broad dependency boundary: one width-affecting change may force many descendants to be reconsidered.

## How do you confirm the regression source?

Capture a slow scroll trace in browser DevTools and separate time into style recalculation, layout, paint, and script. If script is reading layout on every frame, fix that first: the enforced ordering boundary is the browser’s need to finish style and layout before returning those measurements. That turns a cheap scroll into scroll plus synchronous layout work.

Then inventory every `container-type`. Ask two questions: which containers change size during scroll, and how many descendants depend on each one? [MDN’s containment overview](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment) is useful here because its core model is subtree isolation. If a shared query container resizes unnecessarily for independent components, test whether local boundaries reduce work while preserving layout.

## Which invalidation boundaries should you redesign?

Worked example: a feed where each card changes layout based on available width.

Too broad:

```css
.feed-column {
  container-type: inline-size;
}

@container (width > 48rem) {
  .card { grid-template-columns: 2fr 1fr; }
}
```

Here, every card’s query depends on the same column container, so if that container’s relevant size changes, many cards may need to be reconsidered. Confirm that in a trace before redesigning the boundary.

Candidate to measure, with prerequisites: each card must be able to size itself from a local wrapper, and offscreen rows must tolerate deferred rendering.

```css
.card-shell {
  container-type: inline-size;
  contain: layout style;
}

.card-row {
  content-visibility: auto;
  contain-intrinsic-size: auto 20rem;
}
```

Now the query boundary is local to each card, while offscreen rows may allow the browser to skip substantial rendering work until needed, provided your code does not force rendering work on those skipped subtrees. The [web.dev article on `content-visibility`](https://web.dev/content-visibility/) explains that `content-visibility: auto` can let the user agent skip rendering work such as layout and paint for offscreen content, and that `contain-intrinsic-size` supplies a placeholder size so scrolling does not collapse to zero-height boxes.

## What tradeoffs and failure modes matter?

Sticky and overflow come first. If you change overflow to create a different boundary, `position: sticky` may anchor to a different scrolling ancestor and behave differently.

Second, prefer `container-type: inline-size` unless you truly need both axes. As [MDN’s container queries guide](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries) notes, `inline-size` queries the inline dimension and applies layout, style, and inline-size containment, while `size` queries both inline and block dimensions and applies layout, style, and size containment. That stronger contract can change percentage and intrinsic sizing behavior in ways that break existing layouts.

Third, `content-visibility` is not free if your code keeps calling layout-forcing DOM APIs on skipped subtrees. In that case, as [web.dev’s `content-visibility` guidance](https://web.dev/content-visibility/) warns, you can reintroduce the work you meant to avoid.

Decision checklist:

- Trace one bad scroll and identify whether style, layout, paint, or script dominates.
- List query containers that resize during scroll.
- Move the query boundary down to the smallest stable component wrapper.
- Prefer `inline-size` over `size` when width is the only input.
- Add `contain: layout style` only where descendants do not need to affect outside layout.
- Use `content-visibility: auto` plus realistic `contain-intrinsic-size` for long offscreen sections.
- Remove container queries where plain grid or flex rules, such as the fallback patterns noted in [MDN’s container queries guide](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries), solve the same layout locally.

Q: Should every reusable component get its own query container?  
A: No. Give components local query containers only when their own available width is the real decision input.

Q: Does `content-visibility` fix broad invalidation from a shared query container?  
A: Not by itself. First narrow the dependency boundary; then use offscreen skipping to reduce remaining work.

Next step: record one scroll trace, identify the expensive operation, and compare one targeted boundary change against the baseline before adopting it.

Reviewed: 2026-09-06

## Source references

- <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries>
- <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment>
- <https://web.dev/content-visibility/>
