How to use Media Queries in JavaScript

Responsive design is one of the most exciting web layout concepts since CSS replaced tables. The underlying technology uses media queries to determine the viewing device type, width, height, orientation, resolution, aspect ratio, and color depth to serve different stylesheets.

In the following example, cssbasic.css is served to all devices. But, if it’s a screen with a horizontal width of 500 pixels or greater, csswide.css is also sent:


<link rel="stylesheet" media="all" href="cssbasic.css" />
<link rel="stylesheet" media="(min-width: 500px)" href="csswide.css" />

The possibilities are endless and the technique has recently been exploited by sites such as The Boston Globe, Spark Box and Food Sense. Change the width of your browser to discover how the layout changes.

It’s easy to adapt the design or resize elements in CSS. But what if you need to change the content or functionality? For example, on smaller screens you might want to use a shorter headline, a different image, fewer JavaScript libraries, or modify the actions of a widget.

It’s possible to analyze the viewport size in JavaScript but it’s a little messy:

  • Most browsers support window.innerWidth and window.innerHeight.
  • But IE6, 7, 8 and 9 in quirks mode require document.body.clientWidth and document.body.clientHeight.
  • All the main browsers support document.documentElement.clientWidth and document.documentElement.clientHeight but it’s inconsistent. Either the window or document dimensions will be returned depending on the browser and mode.

Detecting screen dimension changes is also possible with window.onresize. However, older versions of IE continually fire this event as the window is altered — it can crash the browser.

Even if you successfully detect viewport dimension changes, you must calculate factors such as orientation and aspect ratios yourself. There’s no guarantee it’ll match your browser’s assumptions when it applies media query rules in CSS.

Modern Media Query Code

Fortunately, it’s now possible to respond to CSS3 media query state changes within JavaScript. The key API is window.matchMedia. This is passed a media query string identical to those used in CSS:


var mq = window.matchMedia( "(min-width: 500px)" );

The matches property returns true or false depending on the query result, e.g.


if (mq.matches) {
	// window width is at least 500px
}
else {
	// window width is less than 500px
}

You can also add an event listener which fires when a change is detected:


// media query event handler
if (matchMedia) {
	var mq = window.matchMedia("(min-width: 500px)");
	mq.addListener(WidthChange);
	WidthChange(mq);
}

// media query change
function WidthChange(mq) {

	if (mq.matches) {
		// window width is at least 500px
	}
	else {
		// window width is less than 500px
	}

}

You should also call the handler directly after defining the event — this will ensure your code can initialize itself during or after the page has loaded. Without it, WidthChange() would never be called if the user did not change their browser dimensions.

Please note that matchMedia is a draft specification so changes may occur. However, it’s already supported by Firefox and Chrome. Safari is unlikely to be far behind and it will appear in IE10 — but possibly using the vendor-prefixed msMatchMedia.

Assuming you’re careful, there’s no reason why you can’t use it today and perhaps fallback to older methods when it’s not supported.

Please view a demonstration page in Firefox or Chrome or download the sample code. Resize the width of your browser window to see layout and “Current Design” text change.

Are you using CSS3 Media Queries? Can you foresee any uses for the matchMedia object?

And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Simply JavaScript.

Comments on this article are closed. Have a question about JavaScript? Why not ask it on our forums?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Tatsh

    Paul Irish wrote a polyfill for browsers that do not support this.
    https://github.com/paulirish/matchMedia.js/blob/master/matchMedia.js

    Also, there is Modernizr.mq() as well.

    The main thing is that I wouldn’t rely upon this that much as most/all presentation should be in CSS not in JavaScript code.

    • http://www.optimalworks.net/ Craig Buckler

      Absolutely – in most cases, changing the layout is all you need. However, functionality could be modified. You could download fewer JavaScript files for smaller devices or you could, for example, change a hover-over menu so it caters for touch events.

  • http://twitter.com/jlbruno Jeff L

    There is also a polyfill by Scott Jehl for browsers that don’t yet support matchMedia:
    https://github.com/scottjehl/matchMedia.js

    • http://www.optimalworks.net/ Craig Buckler

      Thanks for the links.

      The Modernizr and polyfill solutions allow you test the result of a media query by emulating matchMedia.matches. However, they don’t permit you to add an event listener which detects when a change occurs.

  • http://samuli.hakoniemi.net Samuli Hakoniemi

    matchMedia() is also supported by iOS5 Mobile Safari, so it’s clear that “Safari is unlikely to be far behind”, like stated in the article.

  • http://www.howtomake.com.ua HTM

    bigUp man!

  • http://orbital.co.nz Johan

    Looks like it could be used to dynamically set the path for images based on screen width.

  • barry ramsay

    How would you go about using this if you wanted to detect 2 separate but related breakpoints say
    max-width: 760px
    and
    max-width: 480px;

    Would you have to create two separate listeners or could you combine this into one?