Wednesday, August 24, 2022

How to Use the Media Query From JavaScript

How to Use the Media Query From JavaScript

A lot of internet browsing today happens on mobile devices and they come in a variety of sizes. This means that any website that you develop needs to look great at all those sizes. In other words, the website has to be responsive so that its layout can change in response to any changes in screen width.

Using Media Queries in CSS

A popular way of making websites responsive is to use media queries in CSS. Use of media queries allow us to specify which CSS rules should apply to an element at specific screen width. This includes things like changing the font-size for the headings or paragraph text on mobile devices etc.

Consider the following CSS snippet:

We use CSS to tell the browser that the heading needs to be green in color and have a font size of 2rem among other things. However, the font size needs to increase to 4rem whenever the width of screen is larger than 600px. The value of all other CSS properties will remain the same. You can see that that's what happens in real life as well by playing with the CodePen demo below:

Using Media Queries in JavaScript

We can use the same media query that we used above in our JavaScript code. This has been made possible with the help of matchMedia() method that you can call on window.

The matchMedia() method accepts a single single parameter as its value which is the media query that you want to check. Continuing with our example in the previous section, a call to matchMedia() would look like this:

A call to this method returns a MediaQueryList object which contains information on the media query that you applied on the document. It contains two properties. First one is media, which stores the media query as a serialized string. Second one is matches, which is basically a Boolean value that returns true if the media query we supplied as argument matches the document.

A call to matchMedia() won't do much by itself. You need to check whether the matches property of the MediaQueryList object returned by the call is true or false to do your own manipulations. Even then, you will only be able to check whether the media query conditions are met on the initial page load.

What if the user changes the screen width after the initial load? How do you detect that change and act accordingly? This is where an event listener will help us.

There were two methods available to you called addListener() and removeListener() which you could use to listen to any changes in the media query status. However, they are now deprecated.

You should now consider attaching a change event to the MediaQueryList object using the addEventListener() method. Here is what the callback would look like:

The above code will keep track of the screen width when you resize the window and update the text to show a corresponding message about width.

The only thing that is missing from the above code is the initial check to see whether the media query is satisfied when the page is loaded but no resizing has occurred. We can do that check my executing the callback ourselves for the first time.

The CodePen demo below shows how our callback behaves in real life.

Window resize Event Listener Vs matchMedia

Another alternative to the matchMedia() method involves attaching the resize event listener to the window. It is easy to update the code in previous section to use the resize event listener and it would look like this:

This time, we are using the innerWidth property to check if the width is greater than 599 and update the text accordingly. The CodePen demo below shows that we have still got the same functionality that we had when using matchMedia().

It is natural to wonder which of them gives better performance and when should you be using either of these solutions.

Comparing Performance

The resize event listener triggers the widthChangeCallback() function every time the window resizes. This is only required in certain situations where you need to respond to every instance of change in window size such as updating the canvas.

However, there are situations where something needs to happen only when the width or height reaches a certain threshold. One example would be the text updates that we did above. You would get a much better performance with matchMedia() in this case as 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.

Query Complexity

Using matchMedia() method allows you to take advantage of all the power and flexibility provided by media queries. This could be very difficult or down right impossible to replicate by simply using the resize event listener.

While you are limited to width and height when using the traditional resize event listener, you can check a lot more things with the matchMedia() method. Besides the screen width and height, you can use media queries to check the screen resolution, aspect ratio, number of bits per color component, orientation and more.

You can also combine multiple conditions when defining your media queries. The logical operators that you can use include not, and, and only. For example, you can define a media query like this:

Now, attaching a change event listener to our media query object will execute the callback at two different breakpoints.

Lets say that we initially start with a width of 1000px and then start narrowing the window. The callback will be triggered when the width first goes down to 800px. This is because maximum permitted width is 800px. The callback will next be triggered when the screen width goes down to 599px. This is because a minimum width of 600px is still acceptable and state of the media query changes only when width reaches 599px.

Lets say you go down to a width of 400px and then start increasing the width again. Now the media query callback will trigger when the screen width reaches 600px. 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 media queries like aspect-ratio and resolution to do your checks. The aspect ratio is a ratio of the width to height of the viewport. So, a high value for aspect ratio means that the device is in landscape mode. Similarly, a low value for aspect ratio means that the device is in portrait mode. The orientation media query works in a similar manner where the value portrait indicates that the device width 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 proper resources, you can create the appropriate MediaQueryList object by using the following code:

Try opening the CodePen demo below on your mobile devices and you should see the text change to Loading game resources... Something like this wouldn't be possible by just querying the innerWidth of window.

Final Thoughts

In this tutorial, we have covered everything that you need to know about the matchMedia() method and using media queries in JavaScript. We learned that the media queries that we have been using in CSS for a while now can also be used inside JavaScript with the help of the matchMedia() method.

We learned that using matchMedia() gives us better performance instead of adding a resize event listener on window. Similarly, we can perform a lot more checks with media queries compared to the older method which relied on the innerWidth of window to do a few things.

In the end, I would just like to add that matchMedia() enjoys very good browser support over 98%. It is still advisable to make sure that the browsers installed by your target audience support the use of media queries in JavaScript. 

Thumbnail created with Open AI DALL-E.


No comments:

Post a Comment