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!

3 thoughts on “Using Media Queries in JavaScript with enquire.js for Responsive Masonry and More

  1. Hi Morten: Enjoy all of your videos. In regard to the masonry-settings.js, in the downloaded Simone theme your masonry-settings.js file has “masonry” in the file. Is this an error?
    var $container = $(‘#footer-widgets’).masonry();

    Also, in your functions.php file (function simone_scripts()) you have my-sinome when you enqueue some of your styles. This looks like this is a typo for this theme.

    I’ll look forward to your reply and thank you.

    1. Hi Marianne,

      There are several different ways of implementing Masonry. The method you are seeing here (where the masonry() function is mentioned explicitly) is the preferred jQuery method. See http://masonry.desandro.com/#jquery for a default example.

      The mention of “my-sinone” is indeed a typo. It wasn’t caught by the beta testers or myself because it has no effects other than looking weird.

  2. I have tried using enquire js to load masonry at a certain breakpoint. I am displaying the wordpress posts on my blog index page in a masonry layout. I also have the masonry activated on footer, to display the wordpress footer widgets in a masonry layout.

    So basically I have 2 masonry containers on the same page.
    1. One for displaying the blog posts, and
    2. Other for displaying the footer widgets.

    Following is the url where I am trying to implement this layout. — http://lanarratrice-al-rawiya.com/lanarratrice/blog/

    I dont want the masonry to load on the mobile devices.
    1. I want the masonry on Posts to work only when the min width of the document is 837px.
    2. Also I want the masonry on Footer to work only when the min width of the document is 880px.

    Any media query lower than the above width(s) will not trigger the masonry layout, and I will display all my posts and widgets in a full width (taking up the full space available). To implement this I am using enquire js, that will trigger the masonry layout if it matches the media query.

    It seems that my javascript is working correctly, because the masonry layout is implemented. But as I resize my firefox browser window to about 846px (approx around this size), I see a broken layout. I see sometimes that the post is on top of footer. I have also posed this question in StackOverflow. Here is the link – http://stackoverflow.com/questions/28757981/at-a-certain-breakpoint-the-content-from-2-masonry-containers-on-the-same-page

    To reproduce this bug you might have to shrink and expand your browser window (firefox) around 5-8 times. Sometimes if you shrink it very fast or very slow you might not see the broken layout. BTW I am using Firefox 35.0.1. Please let me know what can I do to fix this issue. Thanks.

Comments are closed.