Much of the internet browsing today takes place on mobile devices and they come in a variety of sizes. This means that any website you develop must look good in all those dimensions. In other words, the website needs to be responsive so that its layout can change in response to any change in the screen width.
One popular way to make websites responsive is to use multimedia queries in CSS. Using media queries allows us to specify which CSS rules should be applied to an element with a specific screen width. This includes things like changing the font-size
for titles or paragraph text on mobile devices etc.
Consider the following CSS snippet:
h1 { font-family: 'Lato'; font-size: 2rem; text-transform: uppercase; color: green; } @media (min-width: 600px) { h1 { font-size: 4rem; } }
We use CSS to tell the browser that the header must be green and have a font size of 2rem, among other things. However, the font size must increase to 4rem every time the screen width is greater than 600px. The value of all other CSS properties will remain the same. You can see that this is also what happens in real life by playing with the CodePen demo below:
We can use the same media query we used above in our JavaScript code. This was possible thanks to the help of matchMedia()
method you can use window
.
The matchMedia()
accepts a single single parameter as a value which is the media query you want to check. Continuing with our example in the previous section, a call to matchMedia()
it would look like this:
let myMediaQuery = window.matchMedia('(min-width: 600px)');
A call to this method returns a MediaQueryList
object that contains information about the media query applied to the document. It contains two properties. The first is media
, which stores the media query as a serialized string. The second is matches
which is basically a boolean value that returns true
if the media query we provided as an argument matches the document.
A call to matchMedia()
it won’t do much on its own. You need to check if the matches
property of MediaQueryList
object returned by the call is true
or false
to do your manipulations. Again, you will only be able to check if the media query conditions are met on initial page load.
What if the user changes the screen width after initial loading? How do you detect that change and act accordingly? This is where an event listener will help us.
There were two methods at your disposal called addListener()
And removeListener()
that you could use to listen for any changes to the state of the media query. However, they are now deprecated.
You should now consider attaching a change
event al MediaQueryList
object using the addEventListener()
method. Here’s what the callback would look like:
let myMediaQuery = window.matchMedia('(min-width: 600px)'); function widthChangeCallback(myMediaQuery) { if(myMediaQuery.matches) { document.querySelector("p").textContent = "I am wider than 599px now."; } else { document.querySelector("p").textContent = "I am narrower than 599px now."; } } myMediaQuery.addEventListener('change', widthChangeCallback);
The code above will keep track of the screen width when you resize the window and update the text to show a corresponding message on the width.
The only thing missing from the above code is the initial check to see if the media query is satisfied when the page loads but no scaling has occurred. We can do this by checking my first run of the callback.
widthChangeCallback(myMediaQuery);
The CodePen demo below shows how our callback behaves in real life.
Another alternative to the matchMedia()
the method involves attaching the resize
event listener at the window. It’s easy to update the code in the previous section to use the scaling event listener and it would look like this:
function widthChangeCallback() { if(window.innerWidth > 599) { document.querySelector("p").textContent = "I am wider than 599px now."; } else { document.querySelector("p").textContent = "I am narrower than 599px now."; } } window.addEventListener('resize', widthChangeCallback); widthChangeCallback();
This time we use the innerWidth
to check if the width is greater than 599 and update the text accordingly. The CodePen demo below shows that we still have the same functionality we had while using matchMedia()
.
It is natural to ask which of them performs better and when you should use one of these solutions.
Performance comparison
The resize event listener activates the file widthChangeCallback()
function every time the window resizes. This is only required in certain situations where you need to respond to every instance of changing the window size, such as updating the drawing area.
However, there are situations where something only needs to happen when the width or height reaches a certain threshold. An example would be the text updates we made above. You would get much better performance with matchMedia()
in this case, because it triggers a callback only on actual changes to the media query condition.
Try resizing the window in the CodePen demo below by opening it in a new window and you will see a huge difference in the callback counts.
Complexity of queries
Using matchMedia()
allows you to take advantage of all the power and flexibility provided by media queries. This could be very difficult or even impossible to replicate simply by using the resize
listener of events.
Although you are limited in width and height when using the traditional resize event listener, you can control a lot more things with the matchMedia()
method. In addition to screen width and height, you can use media queries to check screen resolution, aspect ratio, number of bits per color component, orientation, and more.
You can also combine multiple conditions when defining your media queries. Logical operators you can use include not
, and
And only
. For example, you can define a media query like this:
(min-width: 600px) and (max-width: 800px)
Now, attaching a change event listener to our media query object will callback two different breakpoints.
Let’s say we initially start with a width of 1000px and then we start shrinking the window. The callback will be triggered when the width first drops to 800px. This is because the maximum width allowed is 800px. The callback will then be triggered when the screen width drops to 599px. This is because a minimum width of 600px is still acceptable, and the status of the media query only changes when the width reaches 599px.
Let’s say you go down to a width of 400px and then start increasing the width again. Now the media query callback will activate when the screen width reaches 600 pixels. Keep increasing the size and you will see that the fourth callback will be triggered when you reach a width of 801px.
You can also use a combination of other multimedia queries such as aspect-ratio
And resolution
to do your checks. Aspect Ratio is a ratio between the width and height of the window. Hence, a large value for aspect ratio means that the device is in landscape mode. Likewise, a low value for aspect ratio means the device is in portrait mode. The orientation
media query works similarly where the value portrait
indicates that the width of the device is less than or equal to the height.
If you are developing a game where you need the device to be in landscape mode and also need to check its resolution to load the appropriate assets, you can create the MediaQueryList
object using the following code:
let myMediaQuery = window.matchMedia('(min-resolution: 200dpi) and (min-aspect-ratio: 16/9)'); function matchMediaCallback(myMediaQuery) { if(myMediaQuery.matches) { document.querySelector("p").textContent = "Loading game resources.."; } else { document.querySelector("p").textContent = "Please rotate your device"; } } myMediaQuery.addEventListener('change', matchMediaCallback); matchMediaCallback(myMediaQuery);
Try opening the CodePen demo below on your mobile devices and you should see the text change to Loading game assets.. Something like this would not be possible simply by interrogating the innerWidth
of window.
Final thoughts
In this tutorial, we’ve covered everything you need to know about the matchMedia()
method and using media queries in JavaScript. We have learned that the media queries we have been using for a long time in CSS can also be used within JavaScript with the help of the matchMedia()
method.
We learned it using matchMedia()
gives us better performance instead of adding to resize
event listener on the window. Similarly, we can perform many more checks with media queries than the previous method which relied on innerWidth
window to do some things.
In the end, I would just like to add this matchMedia()
enjoys excellent browser support over 98%. However, it is recommended that you ensure that the browsers installed by your target audience support the use of media queries in JavaScript.
Thumbnail created with Open AI DALL-E.