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:
eqio should hopefully be easy to implement in any project with minimal code:
- Add a class of
eqioto the element.
- Add a
data-eqio-sizesattribute whose value is a JSON-serializable array of sizes.
- Optionally add a
data-eqio-prefixattribute whose value is used as the prefix for your class names.
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->700as appropriate. If
data-eqio-prefixhad not been specified, the applied classes would be
Note: Multiple classes can be applied at once.
In your CSS, write class names that match those applied to the HTML.
/* customizations when less than or equal to 400px */
/* customizations when greater than or equal to 700px */
- eqio classes include the special characters
>, so they must be escaped with a
\in your CSS.
- eqio elements are
position: relativeby default, but your component can override that to
fixedetc as required.
- eqio elements can’t be anything but
If using a module bundler, such as webpack, first import
import Eqio from 'eqio';
In your JS, tell eqio which elements are to be made responsive by passing a DOM reference to
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:
This will remove all observers and eqio internals, except for the class names that were applied at the time.
Pretty easy, huh?
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!