Harvey: A Second Face for Your JavaScript

When media queries finally reached a state of good support across a lot of browsers, we started to make our web applications adapt to our users’ devices by optimizing the layout to focus on the content.

But now that we’ve grown to like and incorporate this new adaptive approach, what’s next? We set foot on fairly new grounds not too long ago and so we are still discovering new corners of this land we call Responsive Web Design. One of the things that we will explore next is the ability to add different modes of interaction to our sites, i.e., conditionally executing different JavaScript based on the screen dimensions of the rendering device.

While the browser (or rather, most browsers…) do a pretty good job when it comes to media queries in CSS, there is no easy and, more importantly, simplified tool for the JavaScript camp… until now!

Adapt or Die.

While we were working on the new site for WalkaboutNYC, I ran into different scenarios where it was necessary to change the UI drastically and pull in additional content for larger screens.

We built WalkaboutNYC “mobile first” to ensure that the site — especially the schedule and itinerary pages — was accessible on a wide range of different devices and could easily be used on-the-go by all attendees on the day of the event.

This approach allowed us to focus on only the most important and fundamental content and resulted in a single codebase of clean and semantic markup for the site. However, with increasing screen size, we wanted to enrich the user experience with enhanced navigation elements and offer a wider set of features which went beyond merely changing the layout. We had to change the DOM!

UI elements: Initially, we use native select boxes for more natural UX on small screens (e.g., phones), but then transform them into a list of radio buttons as soon as the screen is wide enough:

External resources: To avoid long load and processing times on small and less capable devices, we decided not to include social media sharing options on those devices. Instead, they are dynamically injected after the page is loaded — and only on large screens:

…Now It’s as Easy as Flipping A Coin

Instead of using the tradional, more cluttered and less reliable methods of checking the screen width in JavaScript and/or listening to window.onresize() to detect changes, I wrote Harvey.

Harvey executes certain parts of your JavaScript depending on the current device’s type, screen size, resolution, orientation, or any of the same media query types you would use in CSS. Harvey is originally written in CoffeeScript, weighs only 3k (1k gzipped) and has no external dependencies.

Once you attach a condition to Harvey (in the form of a valid CSS media query), you can register three callbacks for it. The first one, setup(), will be called the first time your media query becomes valid. The second and third callbacks, on() and off(), are executed each time that media query becomes valid or invalid, respectively:

Harvey.attach('screen and (min-width:600px)', {
    setup:  function() {},
    on:     function() {},
    off:    function() {}
});

Of course, you can attach as many media queries as you want using the same syntax. And all the media queries used in Harvey can be completely independent of the media queries you may be using in your CSS.

Harvey includes a modified version of Scott Jehl's and Paul Irish’s matchMedia polyfill as well as some bug fixes uncovered by Nicholas Zakas. It’s built on top of the matchMedia interface as defined in W3C’s CSSOM View Module.

Get Out There and Explore

Help us push the borders of frontend development to new undiscovered territories! Get the code, find out how it works, and use it in your own projects. Feel free to contribute and to extend Harvey with your own ideas!