Cubit: A More Flexible Media Query

- 30 Comments

mq

This post and idea were developed by Themeco’s lead developers Kory Wakefield and Alexander Rohmann.

Much has been written about the humble media query. In the world of modern web development it is a necessary tool for most all projects, while being equally venerated (yay for responsive design!) and denounced (we need container queries!) at the same time. Media queries do a lot of things very well; however, they also inherently possess shortcomings that pose unique challenges, particularly when constructing tools for others to utilize in a site-building workflow.

Here at Themeco we’re always trying new things, and today we’d like to share an idea we’ve been experimenting with: Cubit. Cubit is a JavaScript library we developed to address some of the pain points mentioned above, which we will walk through in more detail throughout this article.

When you’re done reading, check out the interactive demo and GitHub repo at the bottom of this page.

Specificity vs. Abstraction

As developers, we like our abstractions. It’s always helpful when we can tuck certain details away in a nice, orderly fashion somewhere else and not have to think about the specifics of each layer. With regards to media queries, there isn’t a clean way to do this directly in our stylesheets as we don’t have a dynamic layer to work with:

The code above will always fire when a device’s viewport is at least 1000px wide. This is nice, it’s predictable and works, but it is a rigid construct without any flexibility. What if there were some way to remove this specificity out of the stylesheet? Are there any inherent benefits to doing so?

This infers a similar result, but isn’t tied to any precise figure. Wouldn’t it be powerful to be able to change the meaning of what .lg is expressing behind the scenes from one place? “But muh pre-processors!” I hear you saying. True, tools like Sass allow us to leverage the usefulness of variables and mixins throughout our projects and keep things relatively DRY, but you’re still tied into a specific value. This abstraction could allow you to explore some of the following:

  • Let’s say for the most part you want .lg to represent the same value on your site, but on certain pages you need it to break slightly higher or lower. .lg could represent different values on different pages, but all of your styles can be written in the same syntax throughout your website.
  • If you have a design team that needs to create pages on the fly but doesn’t have access to your development tooling, they can easily style elements as needed using classes like .lg, and if you needed to change the value of what that represents down the road, you could do so without breaking their work or having a mixup of old and new values.
  • If you create products for end-users to build out their own websites (e.g. WordPress themes, et cetera), providing your customers with a way to specify what .lg is and how it works for their needs is a powerful concept. Furthermore, if a user wanted to jump in and make additional customizations beyond the options you provide, it would be a much simpler learning curve for non-technical users to understand our second example from above rather than the first.

Syntax

While it certainly isn’t the most difficult to understand once you get the hang of it, media query syntax can be a bit daunting for newcomers:

I remember having my fair share of moments in my early explorations of responsive design firing up the ol’ Google Machine for a quick refresher on the computational incantations needed to achieve the ideas floating around in my head. Ah, how much simpler the following would have been to experiment with:

Not only that, but let us not forget that ever-important rule when designing for the web: every byte counts! As we all know, in this world nothing can be said to be certain, except death, taxes, and unwieldy stylesheets (Benjamin Franklin was a huge CSS nerd). As time goes on, teams grow, et cetera, unused and unnecessary styles inevitably creep into projects. Sometimes the blessing of pre-processors can also be a curse when left unchecked. You know that awesome mixin you’re using to scatter breakpoints all throughout your stylesheet? It’s spitting out that big mess of characters every time you use it, and in particularly large and complex projects, that adds up. Utilizing a smaller, more abstract syntax allows us to more easily ascertain what is going on with our styles and keeps file size to a minimum (even if handled poorly).

A Thought Experiment

The situations described above (along with a few others) are what prompted us to begin exploring and see if there might be some way to introduce more flexibility into our projects. Specifically for us, the possibility of providing our users with the ability to declare their site-wide breakpoints in one place and then utilize a much cleaner and approachable class-based syntax as needed was a powerful thought. It also meant that we would be able to style site layouts and functionality within a static stylesheet but allow the user to specify what the abstract values we’d be using meant.

A solution like this would obviously require a little JavaScript magic to make use of these techniques, which we only wanted to explore with the following conditions:

  1. All styles should be declared mobile-first so that clients with JavaScript turned off are still able to achieve a good user experience and easily access content.
  2. The script would need to be small and run early enough to output the dynamic responsive classes before our content is visible to avoid FOUC.

The Implementation

As mentioned previously, this is JavaScript powered. If you’ve dabbled in using JavaScript to set styling based on the viewport width, you’ll quickly realize that the units you get from JavaScript do not perfectly match how the viewport is handled in CSS media queries. Libraries like verge help with more accurate approximations (nearly perfect) by normalizing JavaScript’s values depending on the browser.

Enter getComputedStyle! This gem of a function allows you to grab the CSS being applied to any element, at any given moment. Imagine you have this CSS:

Now run this JavaScript:

Depending on your viewport width, style.content will contain: xl, lg, md, sm, or xs! Wrap all this up in a handler on the resize event and you can use media queries to trigger JavaScript changes. The next step would be taking that value and applying it as a class on the html element.

With just a little bit of code, you’ve just abstracted away media queries into simple CSS classes. Now that we’re in JavaScript land, we can take things just a bit farther and bundle this up into a pleasant, little library with one additional goal: have the library generate the required media query CSS from a data attribute, allowing the breakpoints to be determined programmatically when needed.

This opens a new realm of possibilities. Without changing stylesheets themselves, we can change the ranges at which breakpoints trigger. Setting them in a data attribute would allow them to be customized in the options of a theme or plugin.

What’s Next?

It should be noted that Cubit is currently an experimental library. It has significant implications, but isn’t battle tested. Can you break it? Do you see any potential issues with this particular method? Let us know in the comments, or get involved on the GitHub repo.

Playground Github Repo

October 15, 2016 Update:

In response to some of the initial questions we’ve received please read the following.

Wait, doesn’t this violate best practices? Yes, admittedly this introduces another script and breaks one of the old web conventions of not depending on JavaScript. We’re not overly concerned by this, for the following reasons.

Regarding the requiring JavaScript:

  1. The internet these days can’t really be used without JavaScript. Each day this becomes less and less of a concern.
  2. With this technique, the site could still degrade gracefully to any applied mobile first styling.

Regarding performance concerns:

  1. If this is used inline, it will add 1kb to your head. Keep in mind this is smaller than the JavaScript WordPress core (version 4.2) introduced to the head of every site to add the ever so helpful… wait for it… emoji parsing.
  2. When used inline, there’s no measurable speed difference that we can tell in our testing.
  3. Alternatively, it could load as one of the first script requests. This might bump your load time by 50-100ms on the very first load until the browser caches the file for future pages.

What’s the tradeoff? Quick recap:

  1. Less code required in your stylesheets.
  2. Your breakpoints values can change at a site configuration level, without affecting the stylesheets. For example, the same stylesheet is loaded, but different site pages have slightly different/optimized breakpoint values.

Other concerns?

As this is more of an experiment, there’s still some discovery to go before we can decide if this is production worthy. It’s looking promising, but our hope and goal here is that other developers with a grasp of responsive styling challenges will chime in with their thoughts and further testing. We also welcome contributions to our GitHub repo.

October 17th, 2016 Update:

It looks like others are working to solve similar problems in this space! Here are a few links that have been brought to our attention:

Cubit takes this getComputedStyle innovation, packaging it up in a way that will swap any number of classes for you, which can correlate to any breakpoint you wish. We add an additional (and much needed) layer of dynamically generating the stylesheet holding the media queries. This allows for the breakpoints to be set at load, and altered in real time—creating a new dimension of flexibility.

Got anymore links for us? We’d love to know! Obviously this is a pain point that many are working to solve, and we’d love to see some more discussion come from this.

Playground Github Repo

30 Comments on “Cubit: A More Flexible Media Query”

    1. Themeco

      Thanks for checking it out, Alex! Keep in mind that as mentioned in the article, this is currently in an “experimental” phase and we’re simply exploring the idea to see what it yields. If you have any specific feedback, ideas, or want to help us further the library, don’t hesitate to get involved on the GitHub repo!

  1. Jaime

    VERY cool. I’m always adding a ton of media queries because some unwieldy element needs to change at a very odd break point. Looking forward to seeing how this progresses….

    1. Themeco

      Thanks, Jamie! If you have any further ideas or feedback you’d like to share, feel free to add them to the GitHub repo for us to track and look into!

  2. Alejandro

    I love this and i’ll definitely try it out on a few staging sites I have *_* It would definitely help me out a looooot and will surely save me some time and even help write cleaner code wich is always a good thing!

    Me and my team will definitely give it a go and see how it goes :)

    1. Themeco

      Howdy, Alejandro!

      Yes, as long as you feel comfortable working with it “as-is,” understanding it’s still fairly experimental, we’d love to hear some feedback from running it in a live environment. Don’t hesitate to let us know if you need any clarification on anything!

  3. Glenn

    Interesting guys, but doesn’t best practice dictate that CSS comes first and then JavaScript as a fallback? Would the layouts look awful if JavaScript was disabled? Media queries work because they are self contained in the CSS with no script dependencies. Setting custom break points of course is highly advantageous – could it not be achieved with php writing to CSS?

    1. Themeco

      Awesome questions, Glenn! We certainly agree with you that JavaScript should never be used in a manner that hinders the user experience (i.e. content is completely inaccessible, et cetera). Because of this, that’s why we mentioned in the article that using a technique like this along with a mobile first design philosophy ensures that at worst, a user with JavaScript disabled would fallback to a “mobile” design experience. This would likely mean having full-width text and graphics, and a more simplified layout overall, but it certainly wouldn’t mean making content unavailable to the user. Determining what that acceptable fallback layer is for each project is different, so if having your carefully planned “desktop” design visible for all users is important, it might not be for you. That being said, I’ve also found that those browsing the web without JavaScript are likely not the kind of user who cares too much about the overall design aesthetic of a website and is browsing purely with speed and/or content in mind.

      With regards to the PHP side of things, while you could certainly set custom breakpoints in a group of settings and use it to generate CSS, it only gets you about halfway there. First, since you’re using PHP, you’re making server calls to fetch your settings and use it as part of your generated output. Since the server is using that to create all of your output, more work is placed on your server rather than the user’s browser with something like Cubit (it’s always powerful when we can offload things like that to the user when possible). Additionally, you’re still outputting static breakpoints, and since all this is generated, you’re likely outputting it to the <head> of your website over and over again for anything you need, and you can’t access any of those benefits within a static stylesheet. Defining breakpoints once with Cubit and utilizing a class-based approach allows you to access all that power in a static environment like your stylesheets.

  4. Bob

    I’ve always been impressed with your innovative outlook on web design. This is particularly innovative.

    1. Themeco

      Thanks, Bob! We really appreciate that. :) It’s certainly a different take and we’re eager to continue gathering feedback from users on it. If you have any thoughts, we’d love to hear them over on the GitHub repo as well. Cheers!

  5. Shawn

    I like that you all, like a lot of others are moving away from JavaScript. I personally never use it or bootstrap. Media quires rule!!! To re-iterate, when you can get by with less code – you should. Even if it means having to write a little more custom code. Keep it simple and secure – that’s my motto! Happy coding 😉

    1. Themeco

      Howdy, Shawn! Thanks for checking everything out. Just to clarify anything, this implementation does utilize some JavaScript to abstract away the physical media queries from the stylesheet, but does so in a progressive way so that it wouldn’t hinder content accessibility for the user. Check out our “October 15, 2016 Update” section we’ve added to the article as it goes into a little more detail on some of these things. Cheers!

  6. Garratt

    Nice, what I don’t fully grasp though is, I get there is less bytes, But at the same time you’re opening up more files right? So that’s more ping-pong between server and client, which could cause longer load times?

    1. Themeco

      Hey, Garratt! While the GitHub repo talks about adding the script from an external file, it could easily be inlined into the <head> to avoid any extra HTTP requests (which would be ideal), and other than that everything else would function as normal with no additional files. We explain the setup that way on the repo just as a simple “getting started” kind of example, but definitely having it inline would be best.

  7. SURF MERCHANT

    Smart response to responsive versus AMP implementation. With lightweight code frameworks and mobile-first enjoying ever increasing SEO weighting, this is a really progressive development.

    1. Themeco

      Thanks for checking everything out and for your feedback! If you have any ideas or would like to get involved in some way, feel free to check out the GitHub repo and contribute if you’d like. :)

    1. Themeco

      Howdy, Fabio! This is an experimental approach to responsive design that we’ve kicked around for a while and we’re just sharing it to gather ideas from interested developers who may want to contribute or help formulate further ideas around the library.

  8. Matt

    You want to.. speed up a website and abstract out complexity… by using scripts in place of CSS? Good God, why?

    1. Themeco

      Hey, Matt! Thanks for reaching out. Check out the newly added “October 15, 2016 Update” section of the blog post as it addresses some of this. Let us know if you have any other questions or feedback after that and we’d be happy to hear things and discuss. :)

  9. Lucas

    Great to see experimentation guys :) curious though, doesn’t this mean that .lg always needs to be the most “parent” selector in order to apply to an element?

    Works:

    .lg ul li {}

    Doesn’t work:

    ul .lg li {}

    I get that this may seem odd to not put the .lg at the top, but we organise our code into smaller components and using LESS, our selectors are most often out of global scope so using the .lg inline wouldn’t work.

    I think? Keen to keep an eye on this!

    1. Themeco

      Hey, Lucas! Yes, with this particular technique it would mean that .lg would always need to be the most parent selector, but that shouldn’t hinder you from utilizing it within your more modular LESS files. I’m not sure what the syntax would be in LESS, but with Sass you can do the following:

      .el {
      
        .lg & {
          /* styles */
        }
      }

      Which will ultimately output as:

      .lg .el {
        /* styles */
      }

      Even without this, you could still always just create a new section at the bottom of your document for responsive styles and include everything there. The goal with this would be to treat it as similarly to media queries as possible with it “encapsulating” your styles, so you wouldn’t want to use it somewhere in the chain like that. I also find that the more I work with CSS, I try to keep things to one selector as much as possible (maybe a general child or two like <li>, et cetera), but keeping that selector chain short also helps to make styles more manageable.

      Hopefully this helps!

    1. Themeco

      Hey Darren,

      Thanks for writing in and for sharing these links! It’s really cool to see that others are attempting to solve similar problems with varying approaches. :) We will be adding these to our updates section for the article so people can spend some time reading through these additional techniques as well. Cheers!

Leave a Reply to Alejandro Cancel reply

Your email address will not be published. Required fields are marked *