eqio — A simple, tiny alternative to element/container queries

For developers of web-based design systems and component libraries, classic responsive design principles no longer satisfy our needs. If the father of RWD, Ethan Marcotte agrees, you know it’s true.

As we separate our components in to discrete, re-usable pieces with React and Vue, and similarly architect our CSS to match with namespaced classes or CSS-in-JS libraries, everything is wonderful… until it isn’t. When you need to use a component in a completely different context than it was originally created for, or if a component regularly changes to and from various incantations as it changes size, correlating these changes to an arbitrary browser viewport size makes zero sense and creates lots of wasteful CSS.

As hopeful as I am that native Container Queries will one day come to fruition, I cannot wait; I need them now. While there are already multiple attempts to “polyfill” container queries’ behaviour, I wasn’t happy with them for various reasons, so decided to create my own!

eqio uses IntersectionObservers under-the-hood (so is well supported in “good” browsers and easily polyfilled in others) to allow components to adapt their styling based on their width (not the viewport’s) by applying appropriately named classes to the component when its width satisfies your pre-defined requirements.

While eqio, doesn’t support all of the possible use cases for container queries, it supports the two most crucial: adjusting based on a component’s minimum width, and also adapting on a component’s maximum width.

Let’s take a look at a demo:

A demo of eqio running in CodePen: https://codepen.io/stowball/full/zPYzWd/

eqio should hopefully be easy to implement in any project with minimal code:

The HTML

  1. Add a class of eqio to the element.
  2. Add a data-eqio-sizes attribute whose value is a JSON-serializable array of sizes.
  3. Optionally add a data-eqio-prefix attribute whose value is used as the prefix for your class names.
<div
class="media-object eqio"
data-eqio-sizes='["<400", ">700"]'
data-eqio-prefix="media-object"
>

</div>

The above component will:

  • be able to be customised when its width is 400 or smaller ("<" is a synonym for max-width, not “less than”).
  • be able to be customised when its width is 700 or greater (">" is a synonym for min-width, not “greater than”).
  • apply the following classes media-object-eqio-<400 and media-object-eqio->700 as appropriate. If data-eqio-prefix had not been specified, the applied classes would be eqio-<400 and eqio->700.

Note: Multiple classes can be applied at once.

The CSS

In your CSS, write class names that match those applied to the HTML.

.media-object-eqio-\<400 {
/* customizations when less than or equal to 400px */
}
.media-object-eqio-\>700 {
/* customizations when greater than or equal to 700px */
}

Note:

  • eqio classes include the special characters < & >, so they must be escaped with a \ in your CSS.
  • eqio elements are position: relative by default, but your component can override that to absolute/fixedetc as required.
  • eqio elements can’t be anything but overflow: visible.

The JavaScript

If using a module bundler, such as webpack, first import Eqio.

import Eqio from 'eqio';

In your JS, tell eqio which elements are to be made responsive by passing a DOM reference to Eqio.

var mediaObject = new Eqio(document.querySelector('.media-object'));

Should you need to stop this element from being responsive, you can call .stop() on your instance:

mediaObject.stop();

This will remove all observers and eqio internals, except for the class names that were applied at the time.

Pretty easy, huh?


While I’m confident in eqio’s abilities, until native Container Queries are available, I’d recommend using JavaScript alternatives as an enhancement and not a requirement for layout.

To this end, try to separate the CSS that scaffolds the page UI from that of the components. Allow page layout to be handled through media queries, flexbox etc, and ensure that components render as optimally as possible for the majority of users out-of-the-box by enhancing responsive behaviour with flexbox or using Grid where possible before reaching for a Container Queries solution.

Anyway, for more information and installation instructions, see eqio on GitHub. And of course, please let me know what you think!