Container queries shipped cross-browser in 2023, but it took two years for production design systems to actually adopt them. The shift is meaningful: components can now respond to their own container’s size, not just the viewport. A card looks the same in a sidebar, a grid, and a hero, because its layout adapts to the space it has, not to the device the user is on. Here’s the mental shift and how we ship it on FH client sites.
What container queries do
A container query lets a component change its layout based on the size of an ancestor element marked as a container. Unlike a media query (which responds to viewport size), a container query responds to a specific parent. A card placed in a 300px sidebar gets one layout; the same card placed in a 1200px grid gets a different layout — both without changing the component’s code.
/* Mark an element as a container */
.card-container {
container-type: inline-size;
}
/* Component responds to container width */
.card {
display: grid;
grid-template-columns: 1fr;
}
@container (min-width: 480px) {
.card {
grid-template-columns: 1fr 2fr;
}
}
@container (min-width: 720px) {
.card {
grid-template-columns: 1fr 3fr 2fr;
}
}Why this changes design system architecture
Pre-container-queries, a component had to know which breakpoint context it was rendered in. A card in a sidebar needed a `.card--narrow` modifier; a card in a hero needed `.card--wide`. The component’s layout was coupled to the page it lived in. With container queries, the component is self-contained. It responds to its own context. You can drop it anywhere and it works.
How we use container queries on FH client sites
- Project cards: one component definition; renders compactly in sidebars, expansively in galleries.
- Service cards: same component in the home grid (2-column on tablet) and in the solutions page (3-column on desktop).
- Testimonial blocks: stack vertically in narrow containers, side-by-side in wider ones.
- Pricing comparison tables: adjust column count based on container width.
- Blog post cards: scale typography and image size based on container.
Container query units
`cqi` (container query inline-size, ~width) and `cqb` (container query block-size, ~height) let you size things relative to the container. `font-size: 5cqi` means ‘5% of container width.’ Useful for fluid typography that scales smoothly with container, no breakpoint hops.
Browser support
Cross-browser stable since 2023. Safari, Chrome, Firefox, Edge all ship full support. For SMB sites in 2026, container queries are safe to use everywhere. No polyfill required.
When media queries still make sense
- Layout shifts that depend on viewport orientation (portrait vs landscape).
- Device-specific features (`hover: hover`, `pointer: fine` for input capability).
- Theme switches (`prefers-color-scheme`).
- Motion preferences (`prefers-reduced-motion`).
- Print styles (`@media print`).
The mental shift
Designers used to think in pages: ‘at mobile, the page looks like X; at tablet, the page looks like Y; at desktop, the page looks like Z.’ With container queries, the unit of design is the component, not the page. ‘At narrow container, the card looks like X; at wide container, the card looks like Y.’ Pages compose from components that each handle their own responsiveness. The design system becomes more reusable and the layout work is dramatically less repetitive.
Container queries + Tailwind
Tailwind 4 ships first-class container query support. `@container` and `@md:` prefixes (`@md:flex-row`) work alongside `md:` (viewport-based). We use both: viewport queries for page-level layouts, container queries for component-level adjustments.
<div className="@container">
<div className="flex flex-col @md:flex-row gap-4">
<img className="w-full @md:w-1/3" />
<div className="flex-1">
<h3 className="text-lg @lg:text-xl">Title</h3>
<p className="text-sm @lg:text-base">Body</p>
</div>
</div>
</div>Container types: inline-size vs size
`container-type: inline-size` is what you want 95% of the time. It tracks only the inline (horizontal) dimension and doesn’t prevent the container from expanding vertically. `container-type: size` tracks both dimensions but has a side effect: it forces the container to behave as if it has intrinsic size, which often breaks vertical flow. Stick to `inline-size`.
Common pitfalls
- Setting `container-type` and then wondering why the container collapses vertically. Use `inline-size`, not `size`.
- Trying to use container queries to detect viewport size. Use media queries for that.
- Nesting containers without naming them. `container-name: card` lets you target specific containers when nested.
- Forgetting that container queries don’t work for the parent of the component (a component can’t query the container it’s inside without that parent being marked as a container).
Real impact on FH client builds
Reduced component duplication: same card component used in 5 different layout contexts instead of 5 modifier variants. Simpler design system: one source of truth per component. Faster development: build the component once, drop it anywhere. Cleaner CSS: less specificity nesting, fewer overrides. The shift is bigger than ‘a new feature’ — it’s a different way to structure responsive design.
How this lands across FH client work
New FH client builds use container queries by default. Older builds get migrated component-by-component during natural redesigns. The team’s mental model has shifted; the design system has fewer modifiers; the layouts hold up across contexts. If your site’s responsive code is full of `xl:` and `lg:` modifiers and you’re still copy-pasting components for different layout contexts, book a consultation — the migration to container-first is a real architectural improvement.