Motivation
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
http://dev.w3.org/csswg/cssom-view/#widl-Window-matchMedia-MediaQueryLis...
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
| Comment | File | Size | Author |
|---|---|---|---|
| #60 | i1815602-59.patch | 702 bytes | attiks |
| #53 | 1815602_mediaMatch_53.patch | 5.92 KB | attiks |
| #53 | interdiff.txt | 518 bytes | attiks |
| #45 | interdiff.txt | 3.9 KB | attiks |
| #43 | 1815602_mediaMatch_43.patch | 5.97 KB | attiks |
Comments
Comment #1
jessebeach commentedThis 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).
Callbacks can be removed by reference individually or removed as a group by removing the media query referenced by string.
I included the patch file
1815602_testing.txtthat 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.Comment #1.0
jessebeach commentedfixed a grammar mistake: module to modules
Comment #2
jessebeach commentedChanged the title from
"Introduce a JavaScript utility that associates callback functions with media queries"
to
"Introduce a polyfill for matchMedia and MediaQueryList features that associate callback functions with media queries"
Comment #3
jessebeach commentedI 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
resizeandorientationchangeevents 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
MediaQueryListobject, 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.
Comment #3.0
jessebeach commentedadded related issues
Comment #4
jessebeach commentedNeglected to jsHint the code before posting. It's clean now.
Comment #5
attiks commentedNice 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.
Comment #6
wim leersImportant note that I didn't get right away: there aren't any browsers that only implement matchMedia without implementing the MediaQueryList interface.
No spaces around params. See JS coding standards: #172169: [Obsolete] JavaScript coding standards.
1)
windowis 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?
JS coding standards.
Prepend newline.
JS coding standards.
JS coding standards.
Prepend newline.
This isn't about "screen resize or orientationchange", it's about "the associated media query list changes in evaluation".
- 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"?
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.
Prepend newline.
s/'1.0'/VERSION/
Comment #7
wim leersUgh.
Comment #8
attiks commentedFYI: http://caniuse.com/#search=MediaQueryList
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.
Comment #9
wim leersOk 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.
Comment #10
jessebeach commentedIE9 is the big issue. It supports media queries but doesn't implement
matchMediaComment #10.0
jessebeach commentedRemoved text in the description about wrapping the matchMedia function. it was just the wrong approach.
Comment #11
attiks commented@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?
Comment #12
jelle_sHere's a patch based on #11. It uses https://github.com/paulirish/matchMedia.js 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.
Comment #13
jelle_sstatus...
Comment #14
attiks commented"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 http://robnyman.github.com/matchmedia/
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?
Comment #15
jelle_sNew patch based on #14.
Comment #16
jessebeach commentedJelle_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.
Comment #17
attiks commented#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?
Comment #18
jessebeach commentedComment #19
jessebeach commentedI can get a reboot of #4 in place in the next 48 hours. I just want to go through Wim Leers' comments in #6.
Comment #20
gmclelland commentedIsn't this the same issue as #1621594: Media Query Detection?
Comment #21
jessebeach commented@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).
Comment #22
gmclelland commentedClosed 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. https://github.com/JoshBarr/js-media-queries - needs respond.js if supporting IE6-8, no need for matchmedia.js - built in throttling
2. https://github.com/ten1seven/jRespond - 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. https://github.com/paulirish/matchMedia.js - polyfill for browser that don't support matchmedia, no built in throttling but @jessebeach said she wrote in support
4. http://wickynilliams.github.com/enquire.js/ - uses matchmedia.js when matchmedia support is available, if IE6-8 support is needed, then include matchmedia.js - has built in throttling
5. http://harvesthq.github.com/harvey/ - not sure of the browser support, not enough information to make a good decision
6. http://xoxco.com/projects/code/breakpoints/ - checks are based off of screen size - not media query
7. http://rezitech.github.com/syze/ - it looks like check are against screen size not media query, built in throttling
8. https://github.com/martinmartinmartin/breakpoint - 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?
Comment #23
jessebeach commentedWow, awesome roundup @gmclelland!
These are my criteria for success:
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.
Comment #24
gmclelland commentedThanks, 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 http://wickynilliams.github.com/enquire.js/#legacy-support 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!
Comment #25
jessebeach commentedFunny 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.
Comment #26
gmclelland commentedNote: I've never tried any of these libraries. I'm about to start using them after I fully research them.
https://github.com/martinmartinmartin/breakpoint is the only other I think that uses matchmedia.js I'm not sure if it uses it's API?
Comment #27
jessebeach commentedThat breakpoint library wraps matchMedia, but it doesn't polyfill it.
@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.
Comment #28
attiks commented#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:
Comment #29
jessebeach commentedGreat, 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.
Comment #30
attiks commentedWhat is wrong with this solution: https://github.com/paulirish/matchMedia.js/blob/master/matchMedia.addLis...
Comment #31
wim leers#30: It's the inefficient polling approach. See #3.
Comment #32
gmclelland commentedIf interested, here is good article that explains some of Enquire.js http://css-tricks.com/enquire-js-media-query-callbacks-in-javascript/
Comment #33
attiks commentedI knew I missed something ;-)
Comment #34
attiks commentedI have to agree with @gmclelland, enquire.js looks neat, it does what we need, without adding overhead.
Comment #35
jessebeach commentedHere are my concerns with enquire.js:
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
Comment #36
wim leersI'm *very* strongly opposed to enquire.js, for the reasons Jesse outlines. It's a custom API, it is not a polyfill.
https://github.com/wickynilliams/enquire.js
Comment #37
attiks commentedThe problem is that the native listeners are still a bit buggy, that is way they are polling I guess
https://github.com/WickyNilliams/enquire.js/issues/3
https://github.com/paulirish/matchMedia.js/issues/9#issuecomment-8874235
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.
Comment #38
gmclelland commented-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.
True
-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?
True.
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?
Comment #39
attiks commentedSeems I cross posted with #36 if the goal is to have a polyfill, then I guess we need to build it.
Comment #40
attiks commentedLet's stick with the patch in #4, I did some more testing on picture and the problem is that your matchMedia.js defines:
After removing them ie8 "works" again, it can detect the 'screen' media.
I tested your patch using http://robnyman.github.com/matchmedia/, adapted source can be found at https://github.com/attiks/robnyman.github.com/tree/master/matchmedia. It now works for all browsers even IE8
PS: Sorry for all the noise.
Comment #41
jessebeach commentedGood catch! I'll incorporate the change tonight.
Comment #42
jessebeach commented@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.
Comment #43
attiks commented#42 is works, great job!
Attached patch:
Comment #44
wim leers#43:
- 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? :)
Comment #45
attiks commented#44 renamed because all files loaded by the browser are lowercase
Attaching interdiff
Comment #46
jessebeach commentedmost js files are lower-cased (no camels) in /core/misc. I'm fine with the file name change.
Comment #47
jessebeach commentedjshint 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.
Comment #48
gmclelland commented@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.
Comment #49
attiks commentedSince I only did some comment clean up, RTBC from me
Comment #50
wim leersLooks great (note I didn't test) to me. And yes, thank you, @gmclelland for your research — it was most helpful :)
Comment #51
nod_Couple of comments, not enought for putting back in NR but would be nice:
in addListener:
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 http://drupal.org/node/1777342
Comment #52
webchickMarking NW for nod_'s comments, then I'm happy to get this in. Thanks for all the thorough discussion in here.
Comment #53
attiks commentedNew patch
Comment #54
attiks commentedManual test added to http://drupal.org/node/1777342
Comment #55
jessebeach commentedThanks for the update, @attiks. I tested the patch in #53 and it's working fine and dandy.
Comment #56
webchickOk, 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.
Comment #57
attiks commentedChange notice created at http://drupal.org/node/1825832, can somebody check if it makes sense?
Comment #58
wim leers@attiks: Looked great, I created a new revision with minor improvements: "Linked to the specs, s/javascript/JavaScript/, minor clarifications." Thanks! :)
Comment #59
attiks commentedThanks
Comment #60
attiks commentedI 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.
Comment #61
jessebeach commentedI 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.
Comment #62
jessebeach commentedComment #63
webchickOops. Committed and pushed to 8.x. Thanks!
Comment #65
attiks commentedFollow up created #1848500: Use performance optimized matchmedia polyfill
Comment #66
xjmUntagging. Please remove the "Needs change notification" tag when the change notice task is complete.
Comment #67
xjmThose too.
Comment #67.0
xjmadded #1775530: Move picture into core