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.
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!).