Fun with container queries

November 12, 2022


Example of the problem

This first demo is an example of the problem container queries are trying to solve. In this example, I'm simulating a container getting squished by another element on the page.

In this example, media queries are no help to us because the content isn't being squished by a screen size change, but by another element expanding.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur non accumsan augue. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc nec faucibus augue. Aenean accumsan nunc ac dui hendrerit aliquet. Suspendisse imperdiet nulla ex, a tempor mauris maximus eu.

Etiam at commodo dolor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras non ante id arcu pellentesque blandit. Sed tempor consectetur metus, eget ornare lacus eleifend at. Aenean porta augue odio.

Solving with container queries

Here's the same situation but with container queries applied. The interesting part of the code below is where we create a container element from a wrapping div of the component .cq-demo, name it cq-demo, then create a container query with @container syntax.

In this case, we're saying if the width of cq-demo is more than 375px, then display the content area as flex (which creates the two column layout).

.cq-demo {
container: cq-demo / inline-size;
}

.content-area-cq {
display: block;
}

@container cq-demo (min-width: 375px) {
.content-area {
display: flex;
gap: 1rem;
}
}

Container query syntax resources

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur non accumsan augue. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc nec faucibus augue. Aenean accumsan nunc ac dui hendrerit aliquet. Suspendisse imperdiet nulla ex, a tempor mauris maximus eu.

Etiam at commodo dolor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras non ante id arcu pellentesque blandit. Sed tempor consectetur metus, eget ornare lacus eleifend at. Aenean porta augue odio.

As of writing this, container queries are not supported in FireFox, which is honestly a huge bummer. For the project I'm working on, it needs to work in FireFox, and the polyfill (which is cool) isn't feasible for our application

This syntax is super cool and I think it will no doubt be the future of designing flexible layouts. It goes hand-in-hand with how component libraries and design systems are created. For smaller projects, the polyfill could be a good solution but it can cause layout re-rendering and shifting of content which can make your project look janky and fragile.

So how can we get a rock solid container query solution? I ended up going with a ResizeObserver to mimic the functionality of container queries

Solving with a ResizeObserver

var resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
entry.target.classList.remove("cols-1");
entry.target.classList.remove("cols-2");

const { width, height } = entry.contentRect;

if (width < 375) {
entry.target.classList.add("cols-1");
}
if (width >= 375) {
entry.target.classList.add("cols-2");
}
}
});

resizeObserver.observe(document.querySelector('[data-ro="example1"]'));

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur non accumsan augue. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc nec faucibus augue. Aenean accumsan nunc ac dui hendrerit aliquet. Suspendisse imperdiet nulla ex, a tempor mauris maximus eu.

Etiam at commodo dolor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras non ante id arcu pellentesque blandit. Sed tempor consectetur metus, eget ornare lacus eleifend at. Aenean porta augue odio.

Note: Adding too many ResizeObservers is considered a performance liability for large applications. I'm using 3 on one page and the performance isn't terrible, but it could be much smoother. So I'm currently trying to refactor the 3 into 1.

Conclusion

It doesn't feel like container queries are quite ready for production applications unless your organization embraces progressive enhancement (the process by which features are enabled depending on if your browser is capable of handling them). They could be viable for brochure-type websites or small, simple applications. For larger web applications that need to look the same and function the same as much as possible between browsers/devices, container queries don't seem viable.

Adding them in to a SPA would require timely dev work and be a fragile solution since there's a real possibility that a flash of unstyled content will appear before the polyfill kicks in. Using a ResizeObserver is an excellent cross platform solution, but requires some forethought so that you don't end up adding too many and tanking your performance.