Applying CSS styles with media queries is fairly straightforward. Triggering behaviors in JavaScript based on the application of a media query is a little more complicated. It requires registering an event handler against a MediaQueryList event, or, if that isn't implemented in the user agent, polyfilling the functionality.

With the introduction of breakpoint configuration support, Drupal requires a uniform way to handle the association of JavaScript behavior with currently applicable media queries.

The matchMedia global function

The matchMedia function is an emerging standard for testing the applicability of a media query. Chrome 22 and Firefox 15 both implement the specification. Paul Irish put together a polyfill for matchMedia's media query matching. The polyfill will need to be included in this patch.

Is a dependency of

#1775530: Move picture into core

Related issues

#1740422: IE issue: matchMedia() is undefined
#1471638: Add respond.js and matchMedia() polyfill to the whitelist

#60 i1815602-59.patch702 bytesattiks
PASSED: [[SimpleTest]]: [MySQL] 46,349 pass(es).
[ View ]
#53 1815602_mediaMatch_53.patch5.92 KBattiks
PASSED: [[SimpleTest]]: [MySQL] 46,304 pass(es).
[ View ]
#53 interdiff.txt518 bytesattiks
#45 interdiff.txt3.9 KBattiks
#43 1815602_mediaMatch_43.patch5.97 KBattiks
PASSED: [[SimpleTest]]: [MySQL] 46,233 pass(es).
[ View ]
#42 interdiff.txt2.36 KBjessebeach
#42 1815602_mediaMatch_42.patch6.64 KBjessebeach
PASSED: [[SimpleTest]]: [MySQL] 46,230 pass(es).
[ View ]
#15 1815602_mediaMatch_15.patch6.49 KBJelle_S
PASSED: [[SimpleTest]]: [MySQL] 42,806 pass(es).
[ View ]
#12 1815602_mediaMatch_12.patch6.82 KBJelle_S
PASSED: [[SimpleTest]]: [MySQL] 42,801 pass(es).
[ View ]
#12 testing.txt623 bytesJelle_S
#4 1815602_mediaMatch_4.patch6.26 KBjessebeach
PASSED: [[SimpleTest]]: [MySQL] 42,809 pass(es).
[ View ]
#4 testing.txt1.54 KBjessebeach
#3 1815602_mediaMatch_3.patch6.26 KBjessebeach
PASSED: [[SimpleTest]]: [MySQL] 42,814 pass(es).
[ View ]
#3 testing.txt1.54 KBjessebeach
#1 1815602_mediaMatch_1.patch12.54 KBjessebeach
PASSED: [[SimpleTest]]: [MySQL] 42,678 pass(es).
[ View ]
#1 1815602_testing.txt1.49 KBjessebeach


Status:Active» Needs review
new1.49 KB
new12.54 KB
PASSED: [[SimpleTest]]: [MySQL] 42,678 pass(es).
[ View ]

This patch introduces Paul Irish's mediaMatch polyfill.

The polyfill is wrapped in the Drupal.MediaQueryGroup object. Any module can register any number of callbacks against a media query and have them invoked only once per MQ breach, on document load and window resize with some throttling to make sure the resize events don't grind the browser to a halt. Throttling time is configurable through Drupal.settings.

Clients create a new instance of a MediaQueryGroup and add callbacks to the instance with an associated valid media query. A default callback can be added, to be invoked when no other media query in the instance is applicable (this should be the "mobile" case).

  funtion foo () {}
  var mqg = new MediaQueryGroup('myModule');
  mpg.add('default', function () {});
  mpg.add('screen and (min-width: 28em)', foo);

Callbacks can be removed by reference individually or removed as a group by removing the media query referenced by string.

  mpg.remove('screen and (min-width: 28em)');

I included the patch file 1815602_testing.txt that will apply code to the toolbar module to invoke a MediaQueryQuery. Check the console in your browser to see the return value of the current media query callback.

Issue summary:View changes

fixed a grammar mistake: module to modules

Title:Introduce a JavaScript utility that associates callback functions with media queriesIntroduce a polyfill for matchMedia and MediaQueryList features that associate callback functions with media queries

Changed the title from

"Introduce a JavaScript utility that associates callback functions with media queries"


"Introduce a polyfill for matchMedia and MediaQueryList features that associate callback functions with media queries"

new1.54 KB
new6.26 KB
PASSED: [[SimpleTest]]: [MySQL] 42,814 pass(es).
[ View ]

I looked a little more at how to integrate the addListener and removeListener methods into the matchMedia polyfill. I wasn't wild about the polling approach taken by the polyfill for these methods in the Paul Irish's repo. It definitely works. But I don't want the CPU spinning on every page just to check registered media queries against the window dimensions.

So I removed the mediaquerygroup.js file in the patch in #1 and refactored the matchMedia.js file to include support for addListener and removeListener using the resize and orientationchange events on the window. Although not as reliable as the polling method, they are less taxing on the browser.

This updated patch also simulates the MediaQueryList more closely by returning a MediaQueryList object, not just an object literal. The API of the polyfill matches the API in the specification for matchMedia.

I've included a testing patch as well.

Issue summary:View changes

added related issues

new1.54 KB
new6.26 KB
PASSED: [[SimpleTest]]: [MySQL] 42,809 pass(es).
[ View ]

Neglected to jsHint the code before posting. It's clean now.

Issue tags:+Needs tests

Nice work and I completely agree core needs some way to handle this. I'll try to make some time to test this in different browsers.

Status:Needs review» Needs work
Issue tags:-Needs tests

Important note that I didn't get right away: there aren't any browsers that only implement matchMedia without implementing the MediaQueryList interface.

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+  var fakeBody = doc.createElement( "body" );
+  var div = doc.createElement( "div" );

No spaces around params. See JS coding standards: [#172169].

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+  window.addEventListener = window.addEventListener || window.attachEvent || function () {};
+  window.removeEventListener = window.removeEventListener || window.detachEvent || function () {};

1) window is not yet available in the closure.
2) Only IE >=9 supports media queries. IE >=9 also supports addEventListener. So why do we need this then? To make media queries "kind of work" (i.e. only in JS) in IE8?

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+  function MediaQueryList (q) {
+      }(this, debounce(callback, 250)));

JS coding standards.

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+    /**

Prepend newline.

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+      docElem.insertBefore( fakeBody, refNode );

JS coding standards.

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+      docElem.removeChild( fakeBody );

JS coding standards.

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+    /**

Prepend newline.

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+     *   The callback to be invoked on screen resize or orientationchange.

This isn't about "screen resize or orientationchange", it's about "the associated media query list changes in evaluation".

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+     *   query applies to the current screen dimenions and orientation. The

- s/dimenions/dimensions/
- Same as above: why mention screen resize and orientation change if you could just as well just say "media query evaluation has changed"?

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+      }(this, debounce(callback, 250)));

Shouldn't the 250 be in overridable through Drupal.settings? It's okay to default to 250, but for whatever reason we don't know yet, people may want to increase this.

+++ b/core/misc/matchMedia.jsundefined
@@ -0,0 +1,139 @@
+    /**

Prepend newline.

+++ b/core/modules/system/system.moduleundefined
@@ -1380,6 +1380,15 @@ function system_library_info() {
+    'version' => '1.0',


Issue tags:+Needs tests



Regarding IE8, picture (#1775530: Move picture into core), is having the same 'problem', it is using matchmedia.js, and it works depending on the media queries used.

Ok so the IE8 compatibility stuff is needed for e.g. responsive images in IE8 then? That's fine, but then please add a comment stating this should be dropped once IE8 support is dropped from Drupal.

IE9 is the big issue. It supports media queries but doesn't implement matchMedia

Issue summary:View changes

Removed text in the description about wrapping the matchMedia function. it was just the wrong approach.

@wim for the moment picture is using the original matchmedia.js, but we need a standardized way to handle this.

EDIT: picture polyfill.js binds for the moment directly to resize events, so maybe we can use the original match media.js and wrap it so JavaScript can bind to change events?

new623 bytes
new6.82 KB
PASSED: [[SimpleTest]]: [MySQL] 42,801 pass(es).
[ View ]

Here's a patch based on #11. It uses and wraps it to add the addEventListener and removeEventListener. The weird part is that when these functions exist natively (browser supports them), it stops working (evenlisteners aren't triggered for some reason).

Attached is the patch and the lines with which you can test them.

Status:Needs work» Needs review


"evenlisteners aren't triggered for some reason" it depends, it works in Chrome 23.0.1271.40 beta-m/FF 15.0.1, but latest Chromium only fires it at create time, so I guess you need to add them even if the browser supports matchMedia.addEventListener. A quick test can be found at

Re-reading #11: pictfurefill is using matchmedia directyle and isn't (probably) going to use addEventListener to do the evaluation of the media queries, hence the question to not touch matchmedia.js and just add a wrapper.

@jessebeach is this approach/idea acceptable for you?

new6.49 KB
PASSED: [[SimpleTest]]: [MySQL] 42,806 pass(es).
[ View ]

New patch based on #14.

Jelle_S, I'd gone down a similar road with the patch at first to the one you have in #15 thinking that it would good to provide a means to configure the debounce. Then I started thinking about the impact of the configuration. In reality, this will only apply to IE9 and IE8, and then maybe not even IE8 if developers don't care about browsers that don't support media queries anyway. The cost of providing the configuration is the load of drupalSettings for a polyfill that we hope won't be necessary but for 1 or 2 browsers, so it's best to keep the code as light as possible and the dependencies down to zero.

#16 I agree, I rather see drupalSettings not being used in the polyfill, we'll need to keep it as clean as possible.

@jesse this is kind of blocking picture (#1775530: Move picture into core), because we need to decide where to add matchmedia.js, for the moment picture includes a copy of it own. Do you have time to work on this this week so we can move forward? Or do you want me to open a new issue just to add matchmedia.js?

Title:Introduce a polyfill for matchMedia and MediaQueryList features that associate callback functions with media queriesIntroduce a polyfill for matchMedia

I can get a reboot of #4 in place in the next 48 hours. I just want to go through Wim Leers' comments in #6.

Isn't this the same issue as #1621594: Media Query Detection?

@gmclelland, yes, seems to be largely the same. Want to keep this one open since we have patches in it and close the other as a dup (even though it did exist first).

Closed the other issue in favor of this one.

So I'm trying to make sense of all this and here is a brief comparison from what I have seen with the different libraries:

1. - needs respond.js if supporting IE6-8, no need for matchmedia.js - built in throttling

2. - has IE6+ support, has built in throttling, checks are based off of screen size - not media query. Also uses respond.js for IE6-8 mediaquery support

3. - polyfill for browser that don't support matchmedia, no built in throttling but @jessebeach said she wrote in support

4. - uses matchmedia.js when matchmedia support is available, if IE6-8 support is needed, then include matchmedia.js - has built in throttling

5. - not sure of the browser support, not enough information to make a good decision

6. - checks are based off of screen size - not media query

7. - it looks like check are against screen size not media query, built in throttling

8. - checks are against media queries using matchmedia.js similar to Enquire.js but less robust

So without having tested these, it looks like the best route to go is #4 Enquire.js + matchmedia.js (maybe even loaded in with Modernizr(yepnope)).

Here is the links to some issues that this could affect:
#1277352: Responsive vertical tabs
#1510532: [META] Implement the new create content page design
#1276908: Administrative tables are too wide for smaller screens
#1524414: Rewrite tabledrag.js to use jQuery UI
#1137920: Fix toolbar on small screen sizes and redesign toolbar for desktop

@jessebeach what do you think about Enquire.js? Is it needed in this case? Would it be helpful to be in core?

Wow, awesome roundup @gmclelland!

These are my criteria for success:

  • By adhering to the matchMedia and MediaQueryList object API, the code we write against a matchMedia polyfill won't have an abstraction layer between it and the native window.matchMedia method. Ultimately, we just want to use the native method where possible.
  • Any solution that has a dependency on a dependency management or loading management infrastructure is guaranteed to stall. If we need yep/nope in core to load this polyfill, we'll never get this polyfill.
  • The polyfill shouldn't rely on any external libararies. It needs to load fast and for the most part, be dormant.

This is code that will be on every page load because Toolbar is using it. It needs to be super duper tiny. The patch in #4 compresses and gzips down to 948B.

Thanks, It looks like Enquire.js is 2k without gzip, but it is MIT Licensed. I'm assuming it has to be GPL to be included in Drupal?

It doesn't require Modernizr/yepnope I was just suggesting to use if it ever becomes available in Drupal.

It also looks like has good support for old IE.

I'm a little confused on what kind of support for IE does the version of matchmedia.js your working on provide?

-Thank you for everyone's help in pushing Drupal to become responsive!

Funny you should ask :)

The patch in #4 *should* work in IE. My VM install is completely borked at the moment. I need to reset it to get testing. If it does work or just needs a little tweaking, I would advocate for the patch in #4 because it maintains the matchMedia API.

Do any of the other libraries you list maintain the matchMedia API and if so, do you like them? MIT license is fine for Drupal.

Note: I've never tried any of these libraries. I'm about to start using them after I fully research them. is the only other I think that uses matchmedia.js I'm not sure if it uses it's API?

That breakpoint library wraps matchMedia, but it doesn't polyfill it.

To use media queries via window.matchMedia in older browser you can use something like Paul Irish's matchMedia() polyfill. If you're using Modernizr, the same polyfill can be included by checking the Media queries checkbox in the Extra section.

@attiks, do you need an MQ polyfill as well? Or just matchMedia?

matchMedia in a browser that doesn't support MQs will essentially just end up firing the base-case callback (i.e. the mobile).

I tested #4 in IE8 and IE9. They work fine. Fiddling with IE7 a bit.

#27 I'm fine with only matchMedia, MQ polyfill is nice but the patch in #4 doesn't work for picture, I don't get any output in IE8. The original matchMedia.js works with picture in IE8. Using the #4 patch the picturefill code is no longer executed in IE8.

What kind of breakpoints did you use in IE8 to make it work, the picturefill demo site is now running the patch from #4 so other people can test it.

FYI used picture source:

<picture class="resp-img-picture" alt="" title="">
  <source class="image-style-thumbnail" src="" width="100" height="67" alt="">
  <source media="(min-width: 0px)" srcset=" 1x, 2x" class="image-style-thumbnail" width="100" height="67" alt="">
  <source media="screen, all and (min-width: 560px) and (max-width: 850px)" srcset=" 1x, 2x" class="image-style-medium" width="220" height="147" alt="">
  <source media="all and (min-width: 851px)" class="image-style-large" src="" width="480" height="320" alt="">

Great, I'll work from your test case and figure out what's happening. If the patch I have doesn't work, we'll fall back to suggestions from @gmclelland. I've got a few Toolbar issues (#1137920: Fix toolbar on small screen sizes and redesign toolbar for desktop) to work through today and a little cleanup of the Edit module (#1808076: Convert edit module JavaScript to use Create.js, VIE, and Backbone) to get through first, then I can focus on this issue.

#30: It's the inefficient polling approach. See #3.

If interested, here is good article that explains some of Enquire.js

I knew I missed something ;-)

I have to agree with @gmclelland, enquire.js looks neat, it does what we need, without adding overhead.

Here are my concerns with enquire.js:

  • It doesn't back off to window.matchMedia when it's supported.
  • It introduces a custom API.
  • It uses setTimeout to poll for MQ changes -- in all browsers, even if they support window.matchMedia. This imposes a processing cost on what will most likely amount to all pages.
  • We have to add it in addition to the matchMedia polyfill (paulirish).

Do you both agree with my assessment of the deficits of enquire.js? Are you ok with introducing these deficits?

The listen function in enquire.js

* sets up listeners for resize and orientation events
* @function
* @param {int} [timeout=500] the time (in milliseconds) after which the queries should be handled
listen : function(timeout) {
  var eventWireUp = window.addEventListener || window.attachEvent,
    self = this;
  timeout = timeout || 500;
  //prevent multiple event handlers
  if(this.listening) {
    return this;
  //creates closure for separate timed event
  function wireFire(event) {
    var timer;
    eventWireUp(event, function(e) {
      if(timer) {
      timer = setTimeout(function() {;
      }, timeout);
  //handle initial load then listen;
  this.listening = true;
  return this;

I'm *very* strongly opposed to enquire.js, for the reasons Jesse outlines. It's a custom API, it is not a polyfill.

enquire.js is a lightweight, pure javascript framework for programmatically responding to CSS media queries.

The problem is that the native listeners are still a bit buggy, that is way they are polling I guess

Your assessment is correct and if we (you) build it from scratch it will be cleaner, but personally I think the performance impact will be acceptable and the custom API isn't really bothering me.

If you can adopt #4 so it behaves like standard matchmedia.js and it solves your problem for toolbar, great.

It doesn't back off to window.matchMedia when it's supported.

-Maybe this could raised in the enquire.js issue queue. My guess is because it is also checking for orientation changes which might be buggy? Not sure.

It introduces a custom API.


It uses setTimeout to poll for MQ changes -- in all browsers, even if
they support window.matchMedia. This imposes a processing cost on what
will most likely amount to all pages.

-My guess is because it is also checking for orientation changes which might be buggy? Not sure. I wonder how much processing is really used since the calls are throttled?

We have to add it in addition to the matchMedia polyfill (paulirish).


I guess the question is "Is the flexibility it provides worth it and do you see it being used a lot with core and contrib?"

I'm not familar enough with matchmedia.js or enquire.js to make a decision, but I thought I would present it to see if it would be helpful.

If there is any more interest in Enquire.js, I would suggest pulling the author/s into this conversation for better feedback.

Maybe we should list what use cases/problems matchmedia.js and enquire.js could solve if implemented. We have already listed two which is the new toolbar and responsive images.

What others can you think of in core and contrib?

Seems I cross posted with #36 if the goal is to have a polyfill, then I guess we need to build it.

Status:Needs review» Needs work

Let's stick with the patch in #4, I did some more testing on picture and the problem is that your matchMedia.js defines:

window.addEventListener = window.addEventListener || window.attachEvent || function () {};
window.removeEventListener = window.removeEventListener || window.detachEvent || function () {};

After removing them ie8 "works" again, it can detect the 'screen' media.

I tested your patch using, adapted source can be found at It now works for all browsers even IE8

PS: Sorry for all the noise.

Good catch! I'll incorporate the change tonight.

Status:Needs work» Needs review
new6.64 KB
PASSED: [[SimpleTest]]: [MySQL] 46,230 pass(es).
[ View ]
new2.36 KB

@attiks, I changed up the event registration code and tested with success in IE7-IE9. Let me know if the patch works for what you need it for.

interdiff.txt supplied to show changed from #4 to #42.

new5.97 KB
PASSED: [[SimpleTest]]: [MySQL] 46,233 pass(es).
[ View ]

#42 is works, great job!

Attached patch:

  • renames matchMedia.js to matchmedia.js.
  • some minor coding styles and comment fixes.
  • adds window to the closure.

- Why the rename? Just wondering, I have no idea if we have a policy on this sort of thing.
- window in closure: good catch.

Interdiff please? :)

new3.9 KB

#44 renamed because all files loaded by the browser are lowercase

Attaching interdiff

most js files are lower-cased (no camels) in /core/misc. I'm fine with the file name change.

jshint of #43 is clean.

@gmclelland, what do you think of the patch in #43? You've been very active in this thread and I want to make sure we don't discount your opinions. I appreciate the research into alternatives. We have a workable and lean solution proposed here and I'd like to know if we're all ok moving forward with it.

@jessebeach - Thank you for being courteous and asking.

I have seen the work that you, @attiks, and @Wim Leers have done and I respectfully know that everyone here has a far better js knowledge than I.

Just including matchmedia.js is fine with me. My goal was to present the alternatives I've came across so that everyone knows whats available to make an informed decision.

Status:Needs review» Reviewed & tested by the community

Since I only did some comment clean up, RTBC from me

Looks great (note I didn't test) to me. And yes, thank you, @gmclelland for your research — it was most helpful :)

Issue tags:+Needs JS testing

Couple of comments, not enought for putting back in NR but would be nice:

in addListener:

          var self = mql;
          var cb = debounced;

any reason for creating temp variables?

IE8 is a terrible browser, might need a double check to see if we're not facilitating memory leaks on this poor browser.

The JS tests page needs a scenario to test this. No idea how to test properly right now

Status:Reviewed & tested by the community» Needs work

Marking NW for nod_'s comments, then I'm happy to get this in. Thanks for all the thorough discussion in here.

Status:Needs work» Needs review
new518 bytes
new5.92 KB
PASSED: [[SimpleTest]]: [MySQL] 46,304 pass(es).
[ View ]

New patch

Status:Needs review» Reviewed & tested by the community

Manual test added to

Thanks for the update, @attiks. I tested the patch in #53 and it's working fine and dandy.

Title:Introduce a polyfill for matchMediaChange notice: Introduce a polyfill for matchMedia
Priority:Normal» Critical
Status:Reviewed & tested by the community» Active
Issue tags:+Needs change record

Ok, confirmed the license of the upstream library as MIT, which is GPLv2+ compliant. Has sign off from the various JavaScript-ish folks. Is documented, including param documentation.

Committed and pushed to 8.x. Thanks!

Seems like we should have a change notice for this, to let people know about the existence of this library for use in their own modules. Tagging and such.

Change notice created at, can somebody check if it makes sense?

@attiks: Looked great, I created a new revision with minor improvements: "Linked to the specs, s/javascript/JavaScript/, minor clarifications." Thanks! :)

Title:Change notice: Introduce a polyfill for matchMediaIntroduce a polyfill for matchMedia
Assigned:jessebeach» Unassigned
Status:Active» Fixed


Category:task» bug
Priority:Critical» Major
Status:Fixed» Needs review
new702 bytes
PASSED: [[SimpleTest]]: [MySQL] 46,349 pass(es).
[ View ]

I did some more testing, and apparently the specs says that the callback gets executed whenever the state changes, in IE the callback was executed every 250ms, regardless of the state.

Attached patch should fix this.

I tested the patch in #60 and it works. matchMedia only fires once per MQ breakpoint breach.

Do we want to open a new issue since the main issue was closed? I'm fine just putting in this little patch and calling it done.

Status:Needs review» Reviewed & tested by the community

Status:Reviewed & tested by the community» Fixed

Oops. Committed and pushed to 8.x. Thanks!

Status:Fixed» Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Issue tags:-Needs change record

Untagging. Please remove the "Needs change notification" tag when the change notice task is complete.

Those too.