matchMedia (v4)

Revision 4 of this benchmark created on


Description

window.matchMedia vs matchMedia.js polyfill & Media.match

This tests the performance of native window.matchMedia against matchMedia.js and Media.match.

matchMedia() polyfill

Test whether a CSS media type or media query applies. See http://github.com/paulirish/matchMedia.js

Media.match

Testing css media queries in Javascript. Not a polyfill and perhaps faster than native window.matchMedia. See http://github.com/weblinc/media-match

Setup

/* Media - Testing css media queries in Javascript. Authors & copyright (c) 2012: WebLinc, David Knight, Zac Owen. */
    
    (function(d){function q(b){return{name:b||"all",test:function(){return this.name===Media.type}}}function r(b,a,e){var c=Media.features[b];return{name:b,value:a,type:e,test:function(){var a=Media.getAbsValue(this.value);return"min"===this.type?c>a:"max"===this.type?c<a:"undefined"!==this.value?c===a:Number(c)}}}function s(b){var a=f;f++;return{matches:Media.parseMatch(b,!1),media:b,addListener:function(b){Media.queries[a]||(Media.queries[a]={mql:this,listeners:[]});Media.queries[a].listeners.push(b)},
    removeListener:function(b){var c=Media.queries[a];if(c)for(var d=0,g=c.listeners.length;d<g;d++)c.listeners[d]===b&&c.listeners.splice(d,1)}}}function h(b,a,e){return d.getComputedStyle?d.getComputedStyle(b,e||null).getPropertyValue(a):b.currentStyle[a.replace(/-([a-z])/g,function(a,b){return b.toUpperCase()})]}var m=d.document,l=m.getElementsByTagName("head")[0],n=m.documentElement,f=0,p=0;d.Media={supported:1===parseFloat(h(l,"height")),type:"all screen print speech projection handheld tv braille embossed tty".split(" ")[parseFloat(h(l,
    "z-index"))],queries:[],features:{width:0,height:0,"aspect-ratio":0,color:screen.colorDepth,"color-index":Math.pow(2,screen.colorDepth),"device-aspect-ratio":d.devicePixelRatio||(screen.width/screen.height).toFixed(2),"device-width":screen.width,"device-height":screen.height,monochrome:Number(2==screen.colorDepth),orientation:"landscape",resolution:screen.deviceXDPI||parseFloat(h(l,"width"))},getAbsValue:function(b){var a;return(a=b.match(/([\d\.]+)(px|em|rem|%|in|cm|mm|ex|pt|pc)/))?"em"==a[2]?16*
    a[1]:"pt"==a[2]?Media.features.resolution/72*a[1]:parseFloat(a[1]):(a=b.match(/(\d+)[\/:](\d+)/))?a[1]/a[2]:(a=b.match(/([\d]+)(dpi|dpcm)/))?"dpcm"==a[2]?0.3937*a[1]:a[1]:b},parseMatch:function(b,a){var e="string"===typeof b?b.split(", "):b,c=-1!==e[e.length-1].indexOf("not "),d=e.pop(),g="all",i=d.split(" and "),j=i.length-1,f=!c;do{var k=null;if(-1===i[j].indexOf("("))if(g=q(i[j].match(/(not)?\s*(\w*)/)[2]),g.test())continue;else return e.length?this.parseMatch(e,a):c;if((k=i[j].match(/\(\s*(min|max)?-?([^:\s]+)\s*:\s*([^\s]+)\s*\)/))&&
    !r(k[2],k[3],k[1]).test())return e.length?this.parseMatch(e,a):c}while(j--);return a&&f&&{matches:f,type:c?"all, screen, print, speech, projection, handheld, tv, braille, embossed, tty".split(g).join(", ").replace(/(,\s){2}/,""):g,media:d}||f},match:function(b){return new s(b)},watch:function(b){clearTimeout(p);p=setTimeout(function(){var a=f;Media.setMutableFeatures();do{var e=Media.queries[a],c=!1;if("undefined"!==typeof e&&((c=Media.parseMatch(e.mql.media))&&!e.mql.matches||!c&&e.mql.matches)){e.mql.matches=
    c;for(var c=0,h=e.listeners.length;c<h;c++)e.listeners[c]&&e.listeners[c].call(d,e.mql,b)}}while(a--)},10)},setMutableFeatures:function(){Media.features.width=d.innerWidth||n.clientWidth;Media.features.height=d.innerHeight||n.clientHeight;Media.features["aspect-ratio"]=(Media.features.width/Media.features.height).toFixed(2);Media.features.orientatiton=Media.features.height>=Media.features.width?"portrait":"landscape"},listen:function(b){d.addEventListener?(d.addEventListener("resize",b),d.addEventListener("orientationchange",
    b)):d.attachEvent&&(d.attachEvent("onresize",b),d.attachEvent("onorientationchange",b))}};Media.setMutableFeatures();Media.listen(Media.watch)})(window);
                window.matchMediaPolyfill = (function( doc, undefined ) {
    
                  "use strict";
    
                  var bool,
                      docElem = doc.documentElement,
                      refNode = docElem.firstElementChild || docElem.firstChild,
                      // fakeBody required for <FF4 when executed in <head>
                      fakeBody = doc.createElement( "body" ),
                      div = doc.createElement( "div" );
    
                  div.id = "mq-test-1";
                  div.style.cssText = "position:absolute;top:-100em";
                  fakeBody.style.background = "none";
                  fakeBody.appendChild(div);
    
                  return function(q){
    
                    div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
    
                    docElem.insertBefore( fakeBody, refNode );
                    bool = div.offsetWidth === 42;
                    docElem.removeChild( fakeBody );
    
                    return {
                      matches: bool,
                      media: q
                    };
    
                  };
    
                }( document ));

Test runner

Ready to run.

Testing in
TestOps/sec
native matchMedia
window.matchMedia('screen and (min-width: 600px) and (min-height: 400px), screen and (min-height: 400px)');
ready
Media.match
Media.match('screen and (min-width: 600px) and (min-height: 400px), screen and (min-height: 400px)');
ready
polyfill paulirish/scottjehl/matchMedia.js
window.matchMediaPolyfill('screen and (min-width: 600px) and (min-height: 400px), screen and (min-height: 400px)');
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.