├── .gitignore
├── LICENSE.txt
├── README.md
├── bower.json
├── media.match.js
├── media.match.min.js
├── package.json
└── test.html
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build and Release Folders
2 | bin/
3 | bin-debug/
4 | bin-release/
5 |
6 | # Other files and folders
7 | .settings/
8 | .DS_Store
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 WebLinc LLC
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Media.match
2 | ===========
3 |
4 | Test css media queries in javascript. A faster polyfill for matchMedia support. Follow the project on Twitter [@mediamatchjs](https://twitter.com/mediamatchjs).
5 |
6 | Why?
7 | ---
8 | * **Browser support**: Tested in IE 6-9, Chrome, Firefox, Opera, Safari, iOS and Android
9 | * **Feature support**: Has all the basics + most of the spec http://www.w3.org/TR/css3-mediaqueries/
10 | * **Speed**: In many browsers, ops/sec rival or exceed native matchMedia. See 'test' to run your own speed tests using JSLitmus or check out http://jsperf.com/matchmedia/11 and http://jsfiddle.net/wV9HZ/2/
11 | * **Size**: 2.73KB minified (1.46KB gzipped)
12 |
13 | Media type and feature support
14 | ---
15 | * **type**: `all`, `screen`, `print`, `speech`, `projection`, `handheld`, `tv`, `braille`, `embossed`, `tty`
16 | * **width**: `width`, `min-width`, `max-width`
17 | * **height**: `height`, `min-height`, `max-height`
18 | * **device-width**: `device-width`, `min-device-width`, `max-device-width`
19 | * **device-height**: `device-height`, `min-device-height`, `max-device-height`
20 | * **aspect-ratio**: `aspect-ratio`, `min-aspect-ratio`, `max-aspect-ratio`
21 | * **device-aspect-ratio**: `device-aspect-ratio`, `min-device-aspect-ratio`, `max-device-aspect-ratio`
22 | * **orientation**: `orientation`
23 | * **resolution**: `resolution`, `min-resolution`, `max-resolution`
24 | * **device-pixel-ratio**: `device-pixel-ratio`, `min-device-pixel-ratio`, `max-device-pixel-ratio`
25 | * **color**: `color`, `min-color`, `max-color`
26 | * **color-index**: `color-index`, `min-color-index`, `max-color-index`
27 |
28 | ### Lacks support
29 | * **monochrome**: `monochrome`, `min-monochrome`, `max-monochrome`
30 | * **scan**: `scan`
31 | * **grid**: `grid`
32 |
33 | Requirements
34 | ---
35 | #### media.match.min.js/media.match.js
36 | * Provides core functionality. Does not contain external javascript library or css dependencies.
37 | * Version 1 of this project contained a css dependency that is now solely handled by media.match.js. See branch, "version1" for previous iteration.
38 |
39 | Example
40 | ---
41 |
42 | Both code blocks are valid uses of ```matchMedia()```. The first example shows the caching of a ```MediaQueryList``` object and the second shows an alternative usage as well as ```addListener``` support.
43 | The ```addListener``` method is part of the ```MediaQueryList``` object, therefore it can be added on the cached version or immediately after ```matchMedia()```.
44 |
45 | ```
46 |
57 | ```
58 | ```
59 |
69 | ```
70 |
71 | ## Related projects
72 | * [Nonresponsive](https://github.com/weblinc/nonresponsive): Media queries for the unsupportive IE6-8.
73 | * [Picture](https://github.com/weblinc/picture): Responsive images based on the 'picture' element proposal.
74 | * [Img-srcset](https://github.com/weblinc/img-srcset): Responsive images based on the 'srcset' attribute proposal.
75 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "media-match",
3 | "main" :"media.match.js",
4 | "homepage": "https://github.com/weblinc/media-match",
5 | "version": "2.0.3",
6 | "_release": "2.0.3",
7 | "_resolution": {
8 | "type": "version",
9 | "tag": "v2.0.3",
10 | "commit": "8edbaa89dff477ed13107f84b4e74700c17b9382"
11 | },
12 | "_source": "git://github.com/weblinc/media-match.git",
13 | "_target": "~2.0.3",
14 | "_originalSource": "media-match"
15 | }
16 |
--------------------------------------------------------------------------------
/media.match.js:
--------------------------------------------------------------------------------
1 | /*! MediaMatch v.2.0.3 - Testing css media queries in Javascript. Authors & copyright (c) 2013: WebLinc, David Knight. */
2 |
3 | window.matchMedia || (window.matchMedia = function (win) {
4 | 'use strict';
5 |
6 | // Internal globals
7 | var _doc = win.document,
8 | _viewport = _doc.documentElement,
9 | _queries = [],
10 | _queryID = 0,
11 | _type = '',
12 | _features = {},
13 | // only screen
14 | // only screen and
15 | // not screen
16 | // not screen and
17 | // screen
18 | // screen and
19 | _typeExpr = /\s*(only|not)?\s*(screen|print|[a-z\-]+)\s*(and)?\s*/i,
20 | // (-vendor-min-width: 300px)
21 | // (min-width: 300px)
22 | // (width: 300px)
23 | // (width)
24 | // (orientation: portrait|landscape)
25 | _mediaExpr = /^\s*\(\s*(-[a-z]+-)?(min-|max-)?([a-z\-]+)\s*(:?\s*([0-9]+(\.[0-9]+)?|portrait|landscape)(px|em|dppx|dpcm|rem|%|in|cm|mm|ex|pt|pc|\/([0-9]+(\.[0-9]+)?))?)?\s*\)\s*$/,
26 | _timer = 0,
27 |
28 | // Helper methods
29 |
30 | /*
31 | _matches
32 | */
33 | _matches = function (media) {
34 | // screen and (min-width: 400px), screen and (max-width: 500px)
35 | var mql = (media.indexOf(',') !== -1 && media.split(',')) || [media],
36 | mqIndex = mql.length - 1,
37 | mqLength = mqIndex,
38 | mq = null,
39 |
40 | // not screen, screen
41 | negateType = null,
42 | negateTypeFound = '',
43 | negateTypeIndex = 0,
44 | negate = false,
45 | type = '',
46 |
47 | // (min-width: 400px), (min-width)
48 | exprListStr = '',
49 | exprList = null,
50 | exprIndex = 0,
51 | exprLength = 0,
52 | expr = null,
53 |
54 | prefix = '',
55 | length = '',
56 | unit = '',
57 | value = '',
58 | feature = '',
59 |
60 | match = false;
61 |
62 | if (media === '') {
63 | return true;
64 | }
65 |
66 | do {
67 | mq = mql[mqLength - mqIndex];
68 | negate = false;
69 | negateType = mq.match(_typeExpr);
70 |
71 | if (negateType) {
72 | negateTypeFound = negateType[0];
73 | negateTypeIndex = negateType.index;
74 | }
75 |
76 | if (!negateType || ((mq.substring(0, negateTypeIndex).indexOf('(') === -1) && (negateTypeIndex || (!negateType[3] && negateTypeFound !== negateType.input)))) {
77 | match = false;
78 | continue;
79 | }
80 |
81 | exprListStr = mq;
82 |
83 | negate = negateType[1] === 'not';
84 |
85 | if (!negateTypeIndex) {
86 | type = negateType[2];
87 | exprListStr = mq.substring(negateTypeFound.length);
88 | }
89 |
90 | // Test media type
91 | // Test type against this device or if 'all' or empty ''
92 | match = type === _type || type === 'all' || type === '';
93 |
94 | exprList = (exprListStr.indexOf(' and ') !== -1 && exprListStr.split(' and ')) || [exprListStr];
95 | exprIndex = exprList.length - 1;
96 | exprLength = exprIndex;
97 |
98 | if (match && exprIndex >= 0 && exprListStr !== '') {
99 | do {
100 | expr = exprList[exprIndex].match(_mediaExpr);
101 |
102 | if (!expr || !_features[expr[3]]) {
103 | match = false;
104 | break;
105 | }
106 |
107 | prefix = expr[2];
108 | length = expr[5];
109 | value = length;
110 | unit = expr[7];
111 | feature = _features[expr[3]];
112 |
113 | // Convert unit types
114 | if (unit) {
115 | if (unit === 'px') {
116 | // If unit is px
117 | value = Number(length);
118 | } else if (unit === 'em' || unit === 'rem') {
119 | // Convert relative length unit to pixels
120 | // Assumed base font size is 16px
121 | value = 16 * length;
122 | } else if (expr[8]) {
123 | // Convert aspect ratio to decimal
124 | value = (length / expr[8]).toFixed(2);
125 | } else if (unit === 'dppx') {
126 | // Convert resolution dppx unit to pixels
127 | value = length * 96;
128 | } else if (unit === 'dpcm') {
129 | // Convert resolution dpcm unit to pixels
130 | value = length * 0.3937;
131 | } else {
132 | // default
133 | value = Number(length);
134 | }
135 | }
136 |
137 | // Test for prefix min or max
138 | // Test value against feature
139 | if (prefix === 'min-' && value) {
140 | match = feature >= value;
141 | } else if (prefix === 'max-' && value) {
142 | match = feature <= value;
143 | } else if (value) {
144 | match = feature === value;
145 | } else {
146 | match = !!feature;
147 | }
148 |
149 | // If 'match' is false, break loop
150 | // Continue main loop through query list
151 | if (!match) {
152 | break;
153 | }
154 | } while (exprIndex--);
155 | }
156 |
157 | // If match is true, break loop
158 | // Once matched, no need to check other queries
159 | if (match) {
160 | break;
161 | }
162 | } while (mqIndex--);
163 |
164 | return negate ? !match : match;
165 | },
166 |
167 | /*
168 | _setFeature
169 | */
170 | _setFeature = function () {
171 | // Sets properties of '_features' that change on resize and/or orientation.
172 | var w = win.innerWidth || _viewport.clientWidth,
173 | h = win.innerHeight || _viewport.clientHeight,
174 | dw = win.screen.width,
175 | dh = win.screen.height,
176 | c = win.screen.colorDepth,
177 | x = win.devicePixelRatio;
178 |
179 | _features.width = w;
180 | _features.height = h;
181 | _features['aspect-ratio'] = (w / h).toFixed(2);
182 | _features['device-width'] = dw;
183 | _features['device-height'] = dh;
184 | _features['device-aspect-ratio'] = (dw / dh).toFixed(2);
185 | _features.color = c;
186 | _features['color-index'] = Math.pow(2, c);
187 | _features.orientation = (h >= w ? 'portrait' : 'landscape');
188 | _features.resolution = (x && x * 96) || win.screen.deviceXDPI || 96;
189 | _features['device-pixel-ratio'] = x || 1;
190 | },
191 |
192 | /*
193 | _watch
194 | */
195 | _watch = function () {
196 | clearTimeout(_timer);
197 |
198 | _timer = setTimeout(function () {
199 | var query = null,
200 | qIndex = _queryID - 1,
201 | qLength = qIndex,
202 | match = false;
203 |
204 | if (qIndex >= 0) {
205 | _setFeature();
206 |
207 | do {
208 | query = _queries[qLength - qIndex];
209 |
210 | if (query) {
211 | match = _matches(query.mql.media);
212 |
213 | if ((match && !query.mql.matches) || (!match && query.mql.matches)) {
214 | query.mql.matches = match;
215 |
216 | if (query.listeners) {
217 | for (var i = 0, il = query.listeners.length; i < il; i++) {
218 | if (query.listeners[i]) {
219 | query.listeners[i].call(win, query.mql);
220 | }
221 | }
222 | }
223 | }
224 | }
225 | } while(qIndex--);
226 | }
227 |
228 |
229 | }, 10);
230 | },
231 |
232 | /*
233 | _init
234 | */
235 | _init = function () {
236 | var head = _doc.getElementsByTagName('head')[0],
237 | style = _doc.createElement('style'),
238 | info = null,
239 | typeList = ['screen', 'print', 'speech', 'projection', 'handheld', 'tv', 'braille', 'embossed', 'tty'],
240 | typeIndex = 0,
241 | typeLength = typeList.length,
242 | cssText = '#mediamatchjs { position: relative; z-index: 0; }',
243 | eventPrefix = '',
244 | addEvent = win.addEventListener || (eventPrefix = 'on') && win.attachEvent;
245 |
246 | style.type = 'text/css';
247 | style.id = 'mediamatchjs';
248 |
249 | head.appendChild(style);
250 |
251 | // Must be placed after style is inserted into the DOM for IE
252 | info = (win.getComputedStyle && win.getComputedStyle(style)) || style.currentStyle;
253 |
254 | // Create media blocks to test for media type
255 | for ( ; typeIndex < typeLength; typeIndex++) {
256 | cssText += '@media ' + typeList[typeIndex] + ' { #mediamatchjs { position: relative; z-index: ' + typeIndex + ' } }';
257 | }
258 |
259 | // Add rules to style element
260 | if (style.styleSheet) {
261 | style.styleSheet.cssText = cssText;
262 | } else {
263 | style.textContent = cssText;
264 | }
265 |
266 | // Get media type
267 | _type = typeList[(info.zIndex * 1) || 0];
268 |
269 | head.removeChild(style);
270 |
271 | _setFeature();
272 |
273 | // Set up listeners
274 | addEvent(eventPrefix + 'resize', _watch, false);
275 | addEvent(eventPrefix + 'orientationchange', _watch, false);
276 | };
277 |
278 | _init();
279 |
280 | /*
281 | A list of parsed media queries, ex. screen and (max-width: 400px), screen and (max-width: 800px)
282 | */
283 | return function (media) {
284 | var id = _queryID,
285 | mql = {
286 | matches : false,
287 | media : media,
288 | addListener : function addListener(listener) {
289 | _queries[id].listeners || (_queries[id].listeners = []);
290 | listener && _queries[id].listeners.push(listener);
291 | },
292 | removeListener : function removeListener(listener) {
293 | var query = _queries[id],
294 | i = 0,
295 | il = 0;
296 |
297 | if (!query) {
298 | return;
299 | }
300 |
301 | il = query.listeners.length;
302 |
303 | for ( ; i < il; i++) {
304 | if (query.listeners[i] === listener) {
305 | query.listeners.splice(i, 1);
306 | }
307 | }
308 | }
309 | };
310 |
311 | if (media === '') {
312 | mql.matches = true;
313 | return mql;
314 | }
315 |
316 | mql.matches = _matches(media);
317 |
318 | _queryID = _queries.push({
319 | mql : mql,
320 | listeners : null
321 | });
322 |
323 | return mql;
324 | };
325 | }(window));
326 |
--------------------------------------------------------------------------------
/media.match.min.js:
--------------------------------------------------------------------------------
1 | /*! MediaMatch v.2.0.3 - Testing css media queries in Javascript. Authors & copyright (c) 2013: WebLinc, David Knight. */
2 | window.matchMedia||(window.matchMedia=function(e){"use strict";var t=e.document,i=t.documentElement,n=[],s=0,r="",l={},a=/\s*(only|not)?\s*(screen|print|[a-z\-]+)\s*(and)?\s*/i,c=/^\s*\(\s*(-[a-z]+-)?(min-|max-)?([a-z\-]+)\s*(:?\s*([0-9]+(\.[0-9]+)?|portrait|landscape)(px|em|dppx|dpcm|rem|%|in|cm|mm|ex|pt|pc|\/([0-9]+(\.[0-9]+)?))?)?\s*\)\s*$/,d=0,o=function(e){var t=-1!==e.indexOf(",")&&e.split(",")||[e],i=t.length-1,n=i,s=null,d=null,o="",m=0,h=!1,p="",u="",f=null,x=0,v=0,g=null,w="",y="",b="",z="",q="",C=!1;if(""===e)return!0;do if(s=t[n-i],h=!1,d=s.match(a),d&&(o=d[0],m=d.index),!d||-1===s.substring(0,m).indexOf("(")&&(m||!d[3]&&o!==d.input))C=!1;else{if(u=s,h="not"===d[1],m||(p=d[2],u=s.substring(o.length)),C=p===r||"all"===p||""===p,f=-1!==u.indexOf(" and ")&&u.split(" and ")||[u],x=f.length-1,v=x,C&&x>=0&&""!==u)do{if(g=f[x].match(c),!g||!l[g[3]]){C=!1;break}if(w=g[2],y=g[5],z=y,b=g[7],q=l[g[3]],b&&(z="px"===b?Number(y):"em"===b||"rem"===b?16*y:g[8]?(y/g[8]).toFixed(2):"dppx"===b?96*y:"dpcm"===b?.3937*y:Number(y)),C="min-"===w&&z?q>=z:"max-"===w&&z?z>=q:z?q===z:!!q,!C)break}while(x--);if(C)break}while(i--);return h?!C:C},m=function(){var t=e.innerWidth||i.clientWidth,n=e.innerHeight||i.clientHeight,s=e.screen.width,r=e.screen.height,a=e.screen.colorDepth,c=e.devicePixelRatio;l.width=t,l.height=n,l["aspect-ratio"]=(t/n).toFixed(2),l["device-width"]=s,l["device-height"]=r,l["device-aspect-ratio"]=(s/r).toFixed(2),l.color=a,l["color-index"]=Math.pow(2,a),l.orientation=n>=t?"portrait":"landscape",l.resolution=c&&96*c||e.screen.deviceXDPI||96,l["device-pixel-ratio"]=c||1},h=function(){clearTimeout(d),d=setTimeout(function(){var t=null,i=s-1,r=i,l=!1;if(i>=0){m();do if(t=n[r-i],t&&(l=o(t.mql.media),(l&&!t.mql.matches||!l&&t.mql.matches)&&(t.mql.matches=l,t.listeners)))for(var a=0,c=t.listeners.length;c>a;a++)t.listeners[a]&&t.listeners[a].call(e,t.mql);while(i--)}},10)},p=function(){var i=t.getElementsByTagName("head")[0],n=t.createElement("style"),s=null,l=["screen","print","speech","projection","handheld","tv","braille","embossed","tty"],a=0,c=l.length,d="#mediamatchjs { position: relative; z-index: 0; }",o="",p=e.addEventListener||(o="on")&&e.attachEvent;for(n.type="text/css",n.id="mediamatchjs",i.appendChild(n),s=e.getComputedStyle&&e.getComputedStyle(n)||n.currentStyle;c>a;a++)d+="@media "+l[a]+" { #mediamatchjs { position: relative; z-index: "+a+" } }";n.styleSheet?n.styleSheet.cssText=d:n.textContent=d,r=l[1*s.zIndex||0],i.removeChild(n),m(),p(o+"resize",h,!1),p(o+"orientationchange",h,!1)};return p(),function(e){var t=s,i={matches:!1,media:e,addListener:function(e){n[t].listeners||(n[t].listeners=[]),e&&n[t].listeners.push(e)},removeListener:function(e){var i=n[t],s=0,r=0;if(i)for(r=i.listeners.length;r>s;s++)i.listeners[s]===e&&i.listeners.splice(s,1)}};return""===e?(i.matches=!0,i):(i.matches=o(e),s=n.push({mql:i,listeners:null}),i)}}(window));
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "media-match",
3 | "version": "2.0.3",
4 | "description": "Test css media queries in javascript. A faster polyfill for matchMedia support.",
5 | "main": "media.match.js",
6 | "repository": "git@github.com:weblinc/media-match.git",
7 | "author": "David Knight ",
8 | "license": "MIT"
9 | }
10 |
--------------------------------------------------------------------------------
/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
28 |
29 |
30 |
--------------------------------------------------------------------------------