matchMedia vs polyfill

JavaScript performance comparison

Revision 19 of this test case created

Info

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

Preparation code

 
<script>
Benchmark.prototype.setup = function() {
    (function(c){var j=c.document,n=j.getElementsByTagName("head")[0],d=c.getComputedStyle&&c.getComputedStyle(n,null)||n.currentStyle,p=j.documentElement,r=/\(\s*(min|max)?-?([^:\s]+)\s*:\s*([^\s]+)\s*\)/,s=/(not)?\s*(\w*)/,h=0,q=0;c.Media={supported:!1,type:"all",queries:[],features:{width:0,height:0,"aspect-ratio":0,color:screen.colorDepth,"color-index":Math.pow(2,screen.colorDepth),"device-aspect-ratio":(screen.width/screen.height).toFixed(2),"device-width":screen.width,"device-height":screen.height,
    monochrome:Number(2==screen.colorDepth),orientation:"landscape",resolution:96},getAbsValue:function(a){var b;return(b=a.match(/([\d\.]+)(px|em|rem|%|in|cm|mm|ex|pt|pc)/))?"em"==b[2]?16*b[1]:"pt"==b[2]?this.features.resolution/72*b[1]:b[1]:(b=a.match(/(\d+)[\/:](\d+)/))?b[1]/b[2]:(b=a.match(/([\d]+)(dpi|dppx|dpcm)/))?"dpcm"==b[2]?0.3937*b[1]:"dppx"==b[2]?96*b[1]:b[1]:a},parseMatch:function(a,b){var e="string"===typeof a?a.split(", "):a,m=e.pop(),c=-1!==m.indexOf("not "),f="all",k=m.split(" and "),
    l=k.length-1,d=!c;do{var g=null,i=null;if(-1===k[l].indexOf("(")||(g=k[l].match(r))){if(g)var i=this.features[g[2]],h=this.getAbsValue(g[3]),i="min"===g[1]?i>=h:"max"===g[1]?i<=h:"undefined"!==g[3]?i===h:i;else f=k[l].match(s)[2]||f;if(g&&!i||!f===this.type&&"all"!==f)return e.length?this.parseMatch(e,b):c}}while(l--);return b&&d&&{matches:d,type:c?"all, screen, print, speech, projection, handheld, tv, braille, embossed, tty".split(f).join(", ").replace(/(,\s){2}/,""):f,media:m}||d},match:function(a){var b=
    h,a={matches:Media.parseMatch(a,!1),media:a,addListener:function(a){Media.queries[b].listeners||(Media.queries[b].listeners=[]);a&&Media.queries[b].listeners.push(a)},removeListener:function(a){var c=Media.queries[b];if(c)for(var d=0,f=c.listeners.length;d<f;d++)c.listeners[d]===a&&c.listeners.splice(d,1)}};h++;Media.queries.push({mql:a,listeners:null});return a},watch:function(a){clearTimeout(q);q=setTimeout(function(){var b=h;Media.setMutableFeatures();do{var e=Media.queries[b],d=!1;if("undefined"!==
    typeof e&&((d=Media.parseMatch(e.mql.media))&&!e.mql.matches||!d&&e.mql.matches))if(e.mql.matches=d,e.listeners)for(var d=0,j=e.listeners.length;d<j;d++)e.listeners[d]&&e.listeners[d].call(c,e.mql,a)}while(b--)},10)},setMutableFeatures:function(){this.features.width=c.innerWidth||p.clientWidth;this.features.height=c.innerHeight||p.clientHeight;this.features["aspect-ratio"]=(this.features.width/this.features.height).toFixed(2);this.features.orientation=this.features.height>=this.features.width?"portrait":
    "landscape"},listen:function(a){c.addEventListener?(c.addEventListener("resize",a),c.addEventListener("orientationchange",a)):c.attachEvent&&(c.attachEvent("onresize",a),c.attachEvent("onorientationchange",a))},init:function(){this.supported=1===parseFloat(d.height);this.type="all screen print speech projection handheld tv braille embossed tty".split(" ")[parseFloat(d.zIndex)];this.features.resolution=screen.deviceXDPI||parseFloat(d.width);this.setMutableFeatures();this.listen(this.watch)}};Media.init()})(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 ));
};

Benchmark.prototype.teardown = function() {
    Media.queries = [];
   
    if (window.removeEventListener) {
        window.removeEventListener('resize', Media.watch);
        window.removeEventListener('orientationchange', Media.watch);
    } else if (window.detachEvent) {
        window.detachEvent('onresize', Media.watch);
        window.detachEvent('onorientationchange', Media.watch);
    }
};
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

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

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment