Using window.matchMedia to do media queries in JavaScript

For people building web sites, Responsive Web Design has become a natural approach to making sure the content is available for as many users as possible. This is usually attended to via CSS media queries. However, there is a JavaScript alternative as well.

Introducing window.matchMedia

The way to approach media queries in JavaScript is through window.matchMedia. Basically, you just use the same approach as with CSS, but with a JavaScript call:

var widthQuery = window.matchMedia("(min-width: 600px)");

This query returns a MediaQueryList object, on which you can do a few things:

matches
Boolean whether the query matched or not.
media
Serialized media query list.
addListener
Adding event listener to a media query. Much preferred over polling values or similar.
removeListener
Removing event listener from a media query.

Therefore, the easy way to determine if a media query matched is using the matches property:

var widthMatch = window.matchMedia("(min-height: 500px)").matches;

Adding listeners is very easy:

function getOrientationValue (mediaQueryList) {
    console.log(mediaQueryList.matches);
}

portraitOrientationCheck = window.matchMedia("(orientation: portrait)");
portraitOrientationCheck.addListener(getOrientationValue);

Demo and code

I’ve put together a window.matchMedia demo where you can see some queries in action. Try resizing the window and see the values change.

The complete JavaScript code for that demo, which is of course available on GitHub, is as follows:


(function () {
    var matchMediaSupported = document.querySelector("#matchmedia-supported"),
        width600 = document.querySelector("#width-600"),
        height500 = document.querySelector("#height-500"),
        portraitOrientation = document.querySelector("#portrait-orientation"),
        width600Check,
        height500Check,
        portraitOrientationCheck;

    if (window.matchMedia) {
        matchMediaSupported.innerHTML = "supported";

        // Establishing media check
        width600Check = window.matchMedia("(min-width: 600px)"),
        height500Check = window.matchMedia("(min-height: 500px)"),
        portraitOrientationCheck = window.matchMedia("(orientation: portrait)");

        // Add listeners for detecting changes
        width600Check.addListener(setWidthValue);
        height500Check.addListener(setHeightValue);
        portraitOrientationCheck.addListener(setOrientationValue);
    }

    function setWidthValue (mediaQueryList) {
        width600.innerHTML = mediaQueryList.media;
    }

    function setHeightValue (mediaQueryList) {
        height500.innerHTML = mediaQueryList.matches;
    }

    function setOrientationValue (mediaQueryList) {
        portraitOrientation.innerHTML = mediaQueryList.matches;
    }

    // Setting initial values at load
    function setValues () {
        width600.innerHTML = width600Check.matches;
        height500.innerHTML = height500Check.matches;
        portraitOrientation.innerHTML = portraitOrientationCheck.matches;
    }

    window.addEventListener("DOMContentLoaded", setValues, false);
})();

Web browser support

At this time, window.matchMedia has been implemented in:

  • Firefox 6+
  • Google Chrome 9+
  • Safari 5.1+. Note: doesn’t support addListener.
  • Firefox mobile
  • Google Chrome beta on Android. Note: doesn’t support addListener.
  • Safari 5 on iOS. Note: doesn’t support addListener.
  • Android stock browser. Note: doesn’t support addListener.

It is also planned to be in Internet Explorer 10.

For older/unsupported web browsers, you can try the matchMedia() polyfill, although it doesn’t support addListener.

About Robert Nyman [Editor emeritus]

Technical Evangelist & Editor of Mozilla Hacks. Gives talks & blogs about HTML5, JavaScript & the Open Web. Robert is a strong believer in HTML5 and the Open Web and has been working since 1999 with Front End development for the web - in Sweden and in New York City. He regularly also blogs at http://robertnyman.com and loves to travel and meet people.

More articles by Robert Nyman [Editor emeritus]…


15 comments

  1. Moldován Eduárd

    Oh boy, this looks great. I’ll give it a try shortly.

    June 5th, 2012 at 06:34

    1. Robert Nyman

      Cool! Hope it’s useful for you!

      June 6th, 2012 at 23:06

  2. d7ke

    This looks pretty powerful.

    June 5th, 2012 at 13:45

    1. Robert Nyman

      I think so too – a nice complement to media queries in CSS.

      June 6th, 2012 at 23:06

  3. John A. Bilicki III

    Never EVER use the proprietary Microsoft JScript innerHTML method (or related methods) as they do not correctly register nodes in the DOM. To set the text for a node use nodeValue. Examples…

    document.getElementById(‘example-span’).nodeValue = ‘awesome’;

    document.getElementById(‘example-div’).firstChild.nodeValue = ‘awesome’;

    …and even if someone somehow slipped it in to any given standard it does not negate that it’s horribly unreliable to use.

    June 7th, 2012 at 06:30

    1. Robert Nyman

      I don’t necessarily agree with you. It depends on the situation and what you want to do. I wrote about this together with Anne van Kesteren of Opera a long time ago.

      So, yes, there could be potential risks with it, but I don’t personally think it rules out all usages of it.

      June 7th, 2012 at 10:44

  4. John A. Bilicki III

    Robert, what people don’t realize is that it does not actually register the DOM correctly. Try giving focus to an ID loaded via AJAX after the last readyState has closed and them dumped in to the DOM via innerHTML, won’t happen and it’s not limited to giving elements focus either. If adding (X)HTML to the DOM is the equivalent to crowning royalty innerHTML takes the crown and chucks it at the person’s head.

    June 7th, 2012 at 11:30

    1. Robert Nyman

      I’m aware of some of the issues with it, but I don’t think that renders it useless for all cases.

      June 7th, 2012 at 11:52

      1. John A. Bilicki III

        The only instance I ever found it useful for was read-only to look at XHTML directly though now we have Firebug and even without Firebug you can serialize XHTML…

        var c = document.getElementById(‘target_element’).cloneNode(true);
        var s = new XMLSerializer();
        var str = s.serializeToString(c);
        alert(str);

        So read-only would be the at-best for quick debugging though I could never agree to any write operations. Beyond that we will have to agree to disagree. Besides that good article, new code is useless without a good demo that explains not only how to use it though how it can be useful.

        June 7th, 2012 at 12:08

        1. Robert Nyman

          Yes, we’ll agree to disagree then. :-)
          And thanks, glad you liked the article!

          June 8th, 2012 at 02:02

  5. rdeck

    I will put into practice this week end!

    July 17th, 2012 at 03:15

    1. Robert Nyman

      Hope it proved useful!

      July 31st, 2012 at 08:36

  6. Alon

    Thank you so much !!
    was looking for this

    November 8th, 2012 at 02:38

  7. Mat

    Approach is spelt incorrectly in the sentence “The way to approch media queries in JavaScript”. It’s funny because you spelt it correctly on the following line. Great article very useful!

    February 2nd, 2013 at 12:39

    1. Robert Nyman [Editor]

      Thanks! Just a little typo.

      February 4th, 2013 at 03:02

Comments are closed for this article.