One of the hottest concepts right now about the future of CSS involves a new way that styles can apply responsively to elements in a more direct way than currently possible. Today if you are building a website and you want parts of it to change when the browser changes sizes (a phone screen is narrower than a laptop computer's screen) we use a CSS feature called "media queries".

With media queries we are able to wrap a block of CSS styles and leave them disabled. We can add a condition, the most common being min-width and max-width, that would determine when this block of styles is applied. In this sense, media queries act like a container, holding styles for 1 or more elements waiting until a condition is met.

With this in mind, the idea of element queries is to trigger a style change based on some property an individual element on the page has. Where things get a little confusing is that there is no standardized way to write an element query, so each plugin or piece of code that uses the idea has implemented the syntax in a slightly different way.

What's the Difference Between Element Queries and Container Queries?

You will often hear people speaking about element queries and container queries as though the two terms are synonymous, but while element queries can be implemented using the idea of a container query, there are many different ways people have made element queries work:

  • adding custom selectors to CSS
  • adding custom data attributes to HTML elements
  • using JavaScript to apply CSS inline to elements
  • writing a container query in CSS that applies to an element in a responsive way

And still more approaches. There are over a dozen different plugins for element queries right now, and most aren't using container queries.

It makes sense to say not all element queries are container queries, but all container queries are element queries. In fact, you could go so far as to say that media queries are container queries that only work on the root element. Imagine if you could write media queries for individual elements on the page as well.

How Hard is it to Implement Element Queries?

If you want to use the concept of element queries in a project, it only takes ~40 lines of vanilla JavaScript to implement a very basic plugin that will interpret a few responsive conditions on HTML elements using pixel units. This can be implemented within one afternoon, and solves 90% of the use cases for element queries, though by only being able to write element querties (and not container queries) you will end up writing a lot more markup and CSS.

Here's a simple implementation written in an afternoon: Super Simple Element Queries

If you take a week and a few hundred lines of JavaScript to write a plugin, you can write a plugin that understands container queries, and more CSS units besides pixels. The authoring experience and syntax can be nearly identical to writing CSS, minimizing the learning curve for the people working with it, and cutting down on the amount of HTML and CSS required to build the same layout.

With new technologies like Resize Observer and Houdini coming to browsers, we may even be able to write element query and container query plugins that outperform the larger JavaScript plugins in a better performing way in less time than it takes to build a full JavaScript plugin.

Is There a Standard Syntax for Writing Element Queries?

Currently there is no standrdized syntax for element queries, and also no draft or even a proposal. Though websites have been using these concepts for a few years now, discussion around standardizing this functionality is still just getting started.

What would be a huge benefit moving forward as we experiment - even if browsers aren't anxious to implement support, and even if it never gets added to the official CSS spec - would be if those experimenting with the concepts of element queries and container queries could arrive at a powerful syntax that is easy to read, write, and support - so in the meantime while we all wait for support to arrive we can be writing and building sites using these ideas with a way that transfers from codebase to codebase.

It would also be a big benefit if the same syntax could be read the same way by plugins written using vanilla JavaScript, Houdini, or whatever other features that browser supported so the same code could be read by the best plugin that browser can run. Even after Houdini and Resize Observer are released they won't be coming to old browsers like IE8 - so finding a way to minimize fragmentation of our different implementations in the meantime will help minimize technical debt when using these ideas in the future as well.

What is an Example of a Container Query Syntax that Works?

For the past three years I've been searching for, and experimenting with the ideas of element queries and container queries. I've used (and even released plugins for) a number of different syntaxes, and methods of making it work. The most powerful syntax I've used is the @element query syntax we published at http://elementqueries.com (or http://containerqueries.com if you're so inclined). It goes something like this:

If this is a media query that would make the HTML element red when it's greater than 500 pixels wide:

  @media (min-width: 500px) {
  html {
    background: red;
  }
}

A non container query style element query syntax might do something like this if using a custom CSS selector:

  html[width<=500] {
  background: red;
}

Or maybe:

  html[min-width=500] {
  background: red;
}

And another might instead use an HTML attribute in your markup instead to do a very similar thing:

  <html min-width-500="background: red;">    

But in both of these cases the element query plugin syntax is too weak to be able to apply something to the element when the HTML element is wider than 500 pixels.

Thinking of the media query as a container query that is locked to the HTML element (always) we can envision something like this working:

  @media (min-width: 500px) {
  body {
    background: red;
  }
}

We could do that (in theory) with our CSS selector method with something like this, but only because the element is a child of the HTML element:

  html[width<=500] body {
  background: lime;
}

This means using a custom CSS selector we can style descendants below our element, but anybody using our HTML attribute method is powerless to apply a style of body when the HTML element matches its condition.

Thankfully, there is a more powerful syntax for container queries that looks very similar to media queries, just with the addition of an element to set the scope for the repsonsive condition. Imagine this as similar to our media query example above:

  @element 'html' and (min-width: 500px) {
  body {
    background: lime;
  }
}

This functions the same as our media query, but unlike media queries which are permanently locked to the scope of the HTML element at all time we could replace the 'html' element and write queries when any element matches a condition.

How could you write a query that would make the HTML element red when the was wider than 500px? Using our CSS selector we can never reach the HTML element from the element because we have no way of climbing the DOM tree, something like this doesn't work:

  body[width<=500] html {
  background: red;
}

And since there's no '<' selector for selecting a parent, there's just no way for the HTML element to be changed when matches a condition. It is the same with our custom HTML attribute syntax - the only way we could get that to work with our HTML attribute approach is if we contain the entire block of rules in our attribute to be applied when the condition is met:

  <body min-width-500="html {background: red}">

That will function, but is not ideal! That's going to be annoying to have to write full CSS rules in there for each element you add a repsonsive condition to, and inlining styles for one element is messy enough, trying to inline an entire container's worth of queries would make editing the HTML nearly impossible, and likely require a lot of duplication of those attributes throughout your code. If you had a block of styles that applied every time an element met a condition - and you have 15 of those elements on your page, are you then copying those styles verbatim into 15 different (identical) attributes in your HTML?

For an island of sanity in what can quickly become a mess of code, consider this syntax:

  @element 'body' and (min-width: 500px) {
  html {
    background: red;
  }
}

For anybody familiar with writing media queries, this should be immediately legible and they should be able to extend this with very little difficulty…even if they have never run across this syntax before.

Writing @element queries in a similar manner to media queries like this is the only way to reduce the amount of overall HTML and CSS you need to write, instead of adding to it. I think the ability to simplify and reduce code without sacrifice power or flexibility is what sets this syntax apart from other approaches.

The best part is that the syntax used by the EQCSS plugin (and hopefully someday many more plugins) is so close to CSS that most editors with CSS syntax highlighting are fooled into highlighting code written like this as though it's standard CSS.

Where do we go from here?

As we continue building websites and app interfaces with increasingly demanding responsive design to work on an ever diversifying array of devices and browsers, it will become important that we find, settle on, and build toward a common shared syntax when working with (and talking about) element queries and container queries.

After my experimentation, various implementations, and many experiments I still haven't seen or been able to create better syntax than the syntax already supported by EQCSS. Each time I set out with an idea of how another approach might offer a benefit, I always end up falling short and appreciating how powerful EQCSS already is.

I hope that we can standardize and draft up a specification for element queries soon, even if browsers don't move to implement this right away!

If you're looking for a definition of a syntax that works well for container query-style element queries, check out: EQCSS Syntax


2,651 2 13