Getting to Grips with matchMedia

Media Queries are one of my favourite modern web features. The ability to adjust the look and feel of a page based on the device viewing it. Such fun!

There have been numerous occasions over the last few years where I've needed to add classes or do some basic DOM manipulation via JS based on the device viewing the page.

In the past, I've done this by getting the width of the device using $(window).width(); and then using an if statement to add a class to the body of the page depending if it's a large or small device.

var width = $(window).width();
if(width >= 650){
    $('body').addClass('large');
} else {
    $('body').addClass('small');
};

Whilst it works, it's not great. It's handy for a sweeping general statement, if the screen is larger than 650 wide, it's .large otherwise, it's .small... but what about the finer points? That's what I like about media queries; the fact that I can (with the help of a Sass mixin) specify break points with ease and adjust elements with a much finer control.

Fortunately, this is where window.matchMedia comes in. It allows me to run JS on specific size-based elements using a syntax similar to media queries.

So if I wanted to do a similar statement to the code block above, I'd do the following: -

if (window.matchMedia("(min-width: 650px)").matches) {
    $('body').addClass('large');
} else {
   $('body').addClass('small');
}

Now whilst this looks almost identical to the first code block, the difference is that matchMedia is always checking the state of the window. Yes, the first code block can do that, but it'll need to be run within a function that's called every time the window is resized.

So to break that code block down; it starts with an if statement. We feed the window.matchMedia API into the if statement. In this instance, we want our code to fire if the page width is at least 650px so we give the window.matchMedia an argument. In our example, it's "min-width: 650px".

The matchMedia API takes different types of values here. I've used a px value but it can also take em's and rem's. It doesn't appear to take percentages, vh or vw units though, which is a bit of a shame.

Lastly, in order to get this to work, we need to append the .matches method. This provides us with a boolean result depending on the query given.

So basically, if the window.matchMedia("(min-width: 650px)") condition .matches the viewport width, then the boolean will be true and the code will be executed.

Awesome

But even better is that you can attach Listeners to the matchmedia call so that you can then carry out other tasks when matchmedia detects a certain size requirement has been met. Sound complicated?

window.matchMedia('(min-width: 500px)').addListener(function(data) {
    document.getElementById("match").textContent=data.matches;
});

So here, we're checking to see if the browser is at least 500px wide. If it is, we're adding a listener to run a function when it matches. This function replaces the text in #match with either true or false depending on the width. That boolean result comes from the .matches method.

View the Demo

Conclusion

So there we have it, a brief run down of window.matchMedia, a great way to apply the media query method to JS. Also (thanks Nathan), matchMedia is well supported. CanIUse reports at least 90% support for this!).