Beyond CSS Media Queries

Beyond CSS Media Queries

Media queries have been around almost as long as CSS itself — and with no flex, no grid, no responsive units, and no math functions, media queries were the most pragmatic choice available to make a somewhat responsive website.

In the early 2010s, with the proliferation of mobile devices and the timely publication of Ethan Marcotte’s classic article “Responsive Web Design”, media queries became much needed for crafting layouts that could morph across screens and devices. Even when the CSS Flexbox and Grid specifications rolled out, media queries for resizing never left.

While data on the actual usage of media queries is elusive, the fact that they have grown over time with additional features that go well beyond the viewport and into things like user preferences continues to make them a bellwether ingredient for responsive design.

Today, there are more options and tools in CSS for establishing layouts that allow page elements to adapt to many different conditions besides the size of the viewport. Some are more widely used — Flexbox and Grid for certain — but also things like responsive length units and, most notably, container queries, a concept we will come back to in a bit.

But media queries are still often the de facto tool that developers reach for. Maybe it’s muscle memory, inconsistent browser support, or that we’re stuck in our ways, but adoption of the modern approaches we have for responsive interfaces seems slow to take off.

To be clear, I am all for media queries. They play a significant role in the work we do above and beyond watching the viewport size to make better and more accessible user experiences based on a user’s OS preferences, the type of input device they’re using, and more.

But should media queries continue to be the gold standard for responsive layouts? As always, it depends, but

It is undeniable that media queries have evolved toward accessibility solutions, making space for other CSS features to take responsibility for responsiveness.

The Problem With Media Queries

Media queries seemed like a great solution for most responsive-related problems, but as the web has grown towards bigger and more complex layouts, the limits of media queries are more prevalent than ever.

Problem #1: They Are Viewport-Focused

When writing media query breakpoints where we want the layout to adapt, we only have access to the viewport’s properties, like width or orientation. Sometimes, all we need is to tweak a font size, and the viewport is our best bud for that, but most times, context is important.

Components on a page share space with others and are positioned relative to each other according to normal document flow. If all we have access to is the viewport width, knowing exactly where to establish a particular breakpoint becomes a task of compromises where some components will respond well to the adapted layout while others will need additional adjustments at that specific breakpoint.

So, there we are, resizing our browser and looking for the correct breakpoint where our content becomes too squished.

The following example probably has the worst CSS you will see in a while, but it helps to understand one of the problems with media queries.

That same layout in mobile simply does not work. Tables have their own set of responsive challenges as it is, and while there is no shortage of solutions, we may be able to consider another layout using modern techniques that are way less engineered.

We are doing much more than simply changing the width or height of elements! Border colors, element visibility, and flex directions need to be changed, and it can only be done through a media query, right? Well, even in cases where we have to completely switch a layout depending on the viewport size, we can better achieve it with container queries.

Again, Problem #1 of media queries is that they only consider the viewport size when making decisions and are completely ignorant of an element’s surrounding context.

That may not be a big concern if all we’re talking about is a series of elements that are allowed to take up the full page width because the full page width is very much related to the viewport size, making media queries a perfectly fine choice for making adjustments.

See the Pen Responsive Cards Using Media Queries [forked] by Monknow.

But say we want to display those same elements as part of a multi-column layout where they are included in a narrow column as an <aside> next to a larger column containing a <main> element. Now we’re in trouble.

A more traditional solution is to write a series of media queries depending on where the element is used and where its content breaks. But media queries completely miss the relationship between the <main> and <aside> elements, which is a big deal since the size of one influences the size of the other according to normal document flow.

See the Pen Responsive Cards Using Media Queries Inside Container [forked] by Monknow.

The .cards element is in the context of the <aside> element and is squished as a result of being in a narrow column. What would be great is to change the layout of each .card component when the .cards element that contains them reaches a certain size rather than when the viewport is a certain size.

That’s where container queries come into play, allowing us to conditionally apply styles based on an element’s size. We register an element as a “container,” which, in our current example, is the unordered list containing the series of .card components. We’re essentially giving the parent selector a great deal of power to influence the current layout.

.cards {
  container-name: cards;
}

Container queries monitor an element by its size, and we need to tell the browser exactly how to interpret that size by giving .cards a container-type, which can be the container’s size (i.e., in the block and inline directions) or its inline-size (i.e., the total length in the inline direction). There’s a normal value that removes sizing considerations but allows the element to be queried by its styles.

.cards {
  container-name: cards;
  container-type: inline-size;
}

We can simplify things down a bit using the container shorthand property.

.cards {
  container: cards / inline-size;
}

Now, we can adjust the layout of the .card components when the .cards container is a certain inline size. Container queries use the same syntax as media queries but use the @container at-rule instead of @media.

.cards {
  container: cards / inline-size;
}

@container cards (width < 700px) {
  .cards li {
    flex-flow: column;
  }
}

Now, each .card is a flexible container that flows in the column direction when the width of the .cards container is less than 700px. Any wider than that, we have the same to lay them out in a row direction instead.

See the Pen Responsive Cards Using Container Queries [forked] by Monknow.

Style queries are a cousin to container queries in the sense that we can query the container’s styles and conditionally apply style changes to its children, say changing a child element’s color to white when the container’s background-color is set to a dark color. We’re still in the early days, and support for style queries and browser support is still evolving.

I hope this gives you a sense of how amazing it is that we have this context-aware way of establishing responsive layouts. Containers are a completely new idea in CSS (although we’ve used the term synonymously with “parent element” for ages) that is novel and elegant.

So, Are Media Queries Useless?

NO! While media queries have been the go-to solution for responsive design, their limitations are glaringly obvious now that we have more robust tools in CSS that are designed to solve those limits.

That doesn’t make media queries obsolete — merely a different tool that’s part of a larger toolset for building responsive interfaces. Besides, media queries still address vital accessibility concerns thanks to their ability to recognize a user’s visual and motion preferences — among other settings — at the operating system level.

So, yes, keep using media queries! But maybe reach for them sparingly since CSS has a lot more to offer us.