Categories
Tutorials

Using Media Queries in JavaScript with enquire.js for Responsive Masonry and More

Ever wanted to toggle JavaScript on and off with media queries only to discover you cant? Instead you have to write a huge pile of JavaScript to monitor the initial and changing document width and toggle the script on and off manually. This is cumbersome and requires an unreasonable amount of code to do something that should be simple.

Enter enquire.js by Nick Williams: A tiny JavaScript file that allows you to use media queries to toggle JavaScript on and off the same way we use them to toggle CSS on and off. This is such a simple and ingenious solution I had to write a tutorial about it. Bear in mind what I’m showing you here is an extremely simple example. Enquire.js has huge potential that goes far beyond my example. Nevertheless this example should get you up and on your way and will show you how to solve a common and frustrating problem along the way!

Responsive Masonry and other Castles in the Sky

This is the preamble. If you’re just looking for the actual example you can skip this part.

If you scroll to the bottom of my site right now and resize the width of your browser window you’ll see that  the widgets in the footer are tiling and reorganizing in a clean and structured way thanks to Masonry.

Masonry and more evolved varieties like Isotope have changed the way we organize, display, and consume content on the web thanks to their relative responsiveness and ability to take advantage of various changing screen sizes.

The problem with these JavaScript solutions that change the behaviour of your content (Superfish for drop-down menus comes to mind) is that when you display the content on smaller screens you often want these scripts to shut down. In the case of Masonry on this site, when you get to a screen width below 880px wide I no longer want Masonry to be involved. Instead I want the widgets to stack vertically and be full width.

To do this I can write a huge stack of JavaScript as I outlined earlier or I can use the fairly wonky CSS approach recommended by Masonry, but none of this is ideal:

If we approach the problem from a mobile-first perspective we really shouldn’t load Masonry or a script to test whether Masonry should run on smaller devices. It’s a waste of resources and the script just sits there bugging the browser when it shouldn’t be there at all. A better solution would be to only load the script when the screen is or gets wide enough. And that’s exactly what enquire.js lets us do!

Toggling Masonry On and Off with enquire.js

I’m using Masonry as the example here but this same approach can be used for any JavaScript that should change based on media query type events like document width.

Say we have a WordPress site in which we want to control our footer widgets with Masonry. And let’s assume we already have a footer with a widgetized area with the ID #footer-widgets and that each of the widgets has the class .widget. A standard setup in other words.

In this scenario we can deploy Masonry by writing a small script file and pulling the library it right from WordPress core.

The script file, saved in the theme under the /js/ folder with the name masonry-settings.js looks like this:


// Masonry settings to organize footer widgets
jQuery(document).ready(function($){
  var $container = $('#footer-widgets');
  $container.masonry({
    columnWidth: 400,
    itemSelector: '.widget',
    isFitWidth: true,
    isAnimated: true
  });
});

Now we have to enqueue the script and add Masonry as a dependency. This is done in functions.php:


wp_enqueue_script( 'my-masonry', get_template_directory_uri() . '/js/masonry-settings.js', array('masonry'), '20140429', true );

This will make Masonry kick in and set the column width at 400px in the footer which is fine for larger screens. However if you start narrowing the width of  your screen you’ll see this doesn’t work very well.

What we want to do now is toggle Masonry on and off at a certain width breakpoint, in our case 880px: Narrower than 880px and Masonry is not loaded, wider than 880px and Masonry does its thing.

For this we’ll use enquire.js. First get the single enquire.js.min file from the site and dump it in your theme /js/ folder. Next we need to enqueue the file the same way we enqueued our Masonry settings. Enquire has no dependencies so we’ll set the dependency attribute to false:


wp_enqueue_script( 'my-enquire', get_template_directory_uri() . '/js/enquire.min.js', false, '20140429', true );

Now enquire.js is loaded but we need to tell it what to do. Here we’re going to make some modifications to our original masonry-settings.js file to add some media query magic:


// Masonry settings to organize footer widgets
jQuery(document).ready(function($){
  var $container = $('#footer-widgets');
  enquire.register("screen and (min-width:880px)", {

    // Triggered when a media query matches.
    match : function() {
      $container.masonry({
        columnWidth: 400,
        itemSelector: '.widget',
        isFitWidth: true,
        isAnimated: true
      });
    },

    // Triggered when the media query transitions
    // from a matched state to an unmatched state.
    unmatch : function() {
      $container.masonry('destroy');
    }

  });
});

Let’s break it down:

First we register enquire.js and give it a media query:


enquire.register("screen and (min-width:880px)", {}

Then we supply enquire.register with the match and unmatch objects that as their names suggest trigger when the media query either matches (true) or unmatches (false):


enquire.register("screen and (min-width:880px)", {
  // Triggered when a media query matches.
  match : function() {
    // Turn Masonry on
  }

  // Triggered when the media query transitions
  // from a matched state to an unmatched state.
  unmatch : function() {
    // Turn Masonry off using destroy
  }

}

Now all that’s left is slotting in our original Masonry code within Match and call masonry(“destroy”) on unmatch and we’re done!

Other uses (*cough* Superfish *cough*)

Now that you see how easy it is to use enquire.js and how you can mix it in with your JavaScript here is another example of how the script is being used in the current theme you are looking at:

The main menu in this theme is keyboard accessible through its drop-down items (none are present so you just have to trust me on this one). This is achieved using the Superfish jQuery plugin. The problem is on smaller screens the mobile menu kicks in and Superfish goes from being a big help to being a royal pain in the ass. To solve this we need to turn it off when the mobile menu is displayed.

Since we’ve already enqueued enquire.js all we have to do is make some small changes to the /js/superfish-settings.js file:


/* Custom Superfish settings */
jQuery(document).ready(function($){
  var sf= $('ul.nav-menu');
  enquire.register("screen and (min-width:600px)", {

    // Triggered when a media query matches.
    match : function() {
      sf.superfish({
        delay: 200,
        speed: 'fast'
      });
    },

    // Triggered when the media query transitions
    // from a matched state to an unmatched state.
    unmatch : function() {
      sf.superfish('destroy');
    }

  }); 
});

Looks awfully familiar, doesn’t it? That’s because it’s exactly the same thing. So easy and it just works.

Enquire for yourself

Now that you know enquire.js exists and you’ve seen how easy it is to use you need to go out and try it for yourself. Once you’ve done so, report back and let me know how you fared. I’m curious to see what others end up doing with it. I have barely scratched the surface of what’s possible here so there is a world of possibilities waiting to be explored!