1/*! 2 * modernizr v3.3.1 3 * Build http://modernizr.com/download?-csstransforms3d-setclasses-dontmin 4 * 5 * Copyright (c) 6 * Faruk Ates 7 * Paul Irish 8 * Alex Sexton 9 * Ryan Seddon 10 * Patrick Kettner 11 * Stu Cox 12 * Richard Herrera 13 14 * MIT License 15 */ 16 17/* 18 * Modernizr tests which native CSS3 and HTML5 features are available in the 19 * current UA and makes the results available to you in two ways: as properties on 20 * a global `Modernizr` object, and as classes on the `<html>` element. This 21 * information allows you to progressively enhance your pages with a granular level 22 * of control over the experience. 23*/ 24 25;(function(window, document, undefined){ 26 var tests = []; 27 28 29 /** 30 * 31 * ModernizrProto is the constructor for Modernizr 32 * 33 * @class 34 * @access public 35 */ 36 37 var ModernizrProto = { 38 // The current version, dummy 39 _version: '3.3.1', 40 41 // Any settings that don't work as separate modules 42 // can go in here as configuration. 43 _config: { 44 'classPrefix': '', 45 'enableClasses': true, 46 'enableJSClass': true, 47 'usePrefixes': true 48 }, 49 50 // Queue of tests 51 _q: [], 52 53 // Stub these for people who are listening 54 on: function(test, cb) { 55 // I don't really think people should do this, but we can 56 // safe guard it a bit. 57 // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests. 58 // This is in case people listen to synchronous tests. I would leave it out, 59 // but the code to *disallow* sync tests in the real version of this 60 // function is actually larger than this. 61 var self = this; 62 setTimeout(function() { 63 cb(self[test]); 64 }, 0); 65 }, 66 67 addTest: function(name, fn, options) { 68 tests.push({name: name, fn: fn, options: options}); 69 }, 70 71 addAsyncTest: function(fn) { 72 tests.push({name: null, fn: fn}); 73 } 74 }; 75 76 77 78 // Fake some of Object.create so we can force non test results to be non "own" properties. 79 var Modernizr = function() {}; 80 Modernizr.prototype = ModernizrProto; 81 82 // Leak modernizr globally when you `require` it rather than force it here. 83 // Overwrite name so constructor name is nicer :D 84 Modernizr = new Modernizr(); 85 86 87 88 var classes = []; 89 90 91 /** 92 * is returns a boolean if the typeof an obj is exactly type. 93 * 94 * @access private 95 * @function is 96 * @param {*} obj - A thing we want to check the type of 97 * @param {string} type - A string to compare the typeof against 98 * @returns {boolean} 99 */ 100 101 function is(obj, type) { 102 return typeof obj === type; 103 } 104 ; 105 106 /** 107 * Run through all tests and detect their support in the current UA. 108 * 109 * @access private 110 */ 111 112 function testRunner() { 113 var featureNames; 114 var feature; 115 var aliasIdx; 116 var result; 117 var nameIdx; 118 var featureName; 119 var featureNameSplit; 120 121 for (var featureIdx in tests) { 122 if (tests.hasOwnProperty(featureIdx)) { 123 featureNames = []; 124 feature = tests[featureIdx]; 125 // run the test, throw the return value into the Modernizr, 126 // then based on that boolean, define an appropriate className 127 // and push it into an array of classes we'll join later. 128 // 129 // If there is no name, it's an 'async' test that is run, 130 // but not directly added to the object. That should 131 // be done with a post-run addTest call. 132 if (feature.name) { 133 featureNames.push(feature.name.toLowerCase()); 134 135 if (feature.options && feature.options.aliases && feature.options.aliases.length) { 136 // Add all the aliases into the names list 137 for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) { 138 featureNames.push(feature.options.aliases[aliasIdx].toLowerCase()); 139 } 140 } 141 } 142 143 // Run the test, or use the raw value if it's not a function 144 result = is(feature.fn, 'function') ? feature.fn() : feature.fn; 145 146 147 // Set each of the names on the Modernizr object 148 for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) { 149 featureName = featureNames[nameIdx];
150 // Support dot properties as sub tests. We don't do checking to make sure 151 // that the implied parent tests have been added. You must call them in 152 // order (either in the test, or make the parent test a dependency). 153 // 154 // Cap it to TWO to make the logic simple and because who needs that kind of subtesting 155 // hashtag famous last words 156 featureNameSplit = featureName.split('.'); 157 158 if (featureNameSplit.length === 1) { 159 Modernizr[featureNameSplit[0]] = result; 160 } else { 161 // cast to a Boolean, if not one already 162 /* jshint -W053 */ 163 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 164 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 165 } 166 167 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result; 168 } 169 170 classes.push((result ? '' : 'no-') + featureNameSplit.join('-')); 171 } 172 } 173 } 174 } 175 ; 176 177 /** 178 * docElement is a convenience wrapper to grab the root element of the document 179 * 180 * @access private 181 * @returns {HTMLElement|SVGElement} The root element of the document 182 */ 183 184 var docElement = document.documentElement; 185 186 187 /** 188 * A convenience helper to check if the document we are running in is an SVG document 189 * 190 * @access private 191 * @returns {boolean} 192 */ 193 194 var isSVG = docElement.nodeName.toLowerCase() === 'svg'; 195 196 197 /** 198 * setClasses takes an array of class names and adds them to the root element 199 * 200 * @access private 201 * @function setClasses 202 * @param {string[]} classes - Array of class names 203 */ 204 205 // Pass in an and array of class names, e.g.:
206 // ['no-webp', 'borderradius', ...] 207 function setClasses(classes) { 208 var className = docElement.className; 209 var classPrefix = Modernizr._config.classPrefix || ''; 210 211 if (isSVG) { 212 className = className.baseVal; 213 } 214 215 // Change `no-js` to `js` (independently of the `enableClasses` option) 216 // Handle classPrefix on this too 217 if (Modernizr._config.enableJSClass) { 218 var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)'); 219 className = className.replace(reJS, '$1' + classPrefix + 'js$2'); 220 } 221 222 if (Modernizr._config.enableClasses) { 223 // Add the new classes 224 className += ' ' + classPrefix + classes.join(' ' + classPrefix); 225 isSVG ? docElement.className.baseVal = className : docElement.className = className; 226 } 227 228 } 229 230 ; 231 232 /** 233 * If the browsers follow the spec, then they would expose vendor-specific style as: 234 * elem.style.WebkitBorderRadius 235 * instead of something like the following, which would be technically incorrect: 236 * elem.style.webkitBorderRadius 237 238 * Webkit ghosts their properties in lowercase but Opera & Moz do not. 239 * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ 240 * erik.eae.net/archives/2008/03/10/21.48.10/ 241 242 * More here: github.com/Modernizr/Modernizr/issues/issue/21 243 * 244 * @access private 245 * @returns {string} The string representing the vendor-specific style properties 246 */ 247 248 var omPrefixes = 'Moz O ms Webkit'; 249 250 251 var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []); 252 ModernizrProto._cssomPrefixes = cssomPrefixes; 253 254 255 256 /** 257 * contains checks to see if a string contains another string 258 * 259 * @access private 260 * @function contains 261 * @param {string} str - The string we want to check for substrings 262 * @param {string} substr - The substring we want to search the first string for 263 * @returns {boolean} 264 */ 265 266 function contains(str, substr) { 267 return !!~('' + str).indexOf(substr); 268 } 269 270 ; 271 272 /** 273 * createElement is a convenience wrapper around document.createElement. Since we 274 * use createElement all over the place, this allows for (slightly) smaller code 275 * as well as abstracting away issues with creating elements in contexts other than 276 * HTML documents (e.g. SVG documents). 277 * 278 * @access private 279 * @function createElement 280 * @returns {HTMLElement|SVGElement} An HTML or SVG element 281 */ 282 283 function createElement() { 284 if (typeof document.createElement !== 'function') { 285 // This is the case in IE7, where the type of createElement is "object". 286 // For this reason, we cannot call apply() as Object is not a Function. 287 return document.createElement(arguments[0]); 288 } else if (isSVG) { 289 return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]); 290 } else { 291 return document.createElement.apply(document, arguments); 292 } 293 } 294 295 ; 296 297 /** 298 * Create our "modernizr" element that we do most feature tests on. 299 * 300 * @access private 301 */ 302 303 var modElem = { 304 elem: createElement('modernizr') 305 }; 306 307 // Clean up this element 308 Modernizr._q.push(function() { 309 delete modElem.elem; 310 }); 311 312 313 314 var mStyle = { 315 style: modElem.elem.style 316 }; 317 318 // kill ref for gc, must happen before mod.elem is removed, so we unshift on to 319 // the front of the queue. 320 Modernizr._q.unshift(function() { 321 delete mStyle.style; 322 }); 323 324 325 326 /** 327 * getBody returns the body of a document, or an element that can stand in for 328 * the body if a real body does not exist 329 * 330 * @access private 331 * @function getBody 332 * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an 333 * artificially created element that stands in for the body 334 */ 335 336 function getBody() { 337 // After page load injecting a fake body doesn't work so check if body exists 338 var body = document.body; 339 340 if (!body) { 341 // Can't use the real body create a fake one. 342 body = createElement(isSVG ? 'svg' : 'body'); 343 body.fake = true; 344 } 345 346 return body; 347 } 348 349 ; 350 351 /** 352 * injectElementWithStyles injects an element with style element and some CSS rules 353 * 354 * @access private 355 * @function injectElementWithStyles 356 * @param {string} rule - String representing a css rule 357 * @param {function} callback - A function that is used to test the injected element 358 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 359 * @param {string[]}
359 [testnames] - An array of strings that are used as ids for the additional nodes 360 * @returns {boolean} 361 */ 362 363 function injectElementWithStyles(rule, callback, nodes, testnames) { 364 var mod = 'modernizr'; 365 var style; 366 var ret; 367 var node; 368 var docOverflow; 369 var div = createElement('div'); 370 var body = getBody(); 371 372 if (parseInt(nodes, 10)) { 373 // In order not to give false positives we create a node for each test 374 // This also allows the method to scale for unspecified uses 375 while (nodes--) { 376 node = createElement('div'); 377 node.id = testnames ? testnames[nodes] : mod + (nodes + 1); 378 div.appendChild(node); 379 } 380 } 381 382 style = createElement('style'); 383 style.type = 'text/css'; 384 style.id = 's' + mod; 385 386 // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody. 387 // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270 388 (!body.fake ? div : body).appendChild(style); 389 body.appendChild(div); 390 391 if (style.styleSheet) { 392 style.styleSheet.cssText = rule; 393 } else { 394 style.appendChild(document.createTextNode(rule)); 395 } 396 div.id = mod; 397 398 if (body.fake) { 399 //avoid crashing IE8, if background image is used 400 body.style.background = ''; 401 //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible 402 body.style.overflow = 'hidden'; 403 docOverflow = docElement.style.overflow; 404 docElement.style.overflow = 'hidden'; 405 docElement.appendChild(body); 406 } 407 408 ret = callback(div, rule); 409 // If this is done after page load we don't want to remove the body so check if body exists 410 if (body.fake) { 411 body.parentNode.removeChild(body); 412 docElement.style.overflow = docOverflow; 413 // Trigger layout so kinetic scrolling isn't disabled in iOS6+ 414 docElement.offsetHeight; 415 } else { 416 div.parentNode.removeChild(div); 417 } 418 419 return !!ret; 420 421 } 422 423 ; 424 425 /** 426 * domToCSS takes a camelCase string and converts it to kebab-case 427 * e.g. boxSizing -> box-sizing 428 * 429 * @access private 430 * @function domToCSS 431 * @param {string} name - String name of camelCase prop we want to convert 432 * @returns {string} The kebab-case version of the supplied name 433 */ 434 435 function domToCSS(name) { 436 return name.replace(/([A-Z])/g, function(str, m1) { 437 return '-' + m1.toLowerCase(); 438 }).replace(/^ms-/, '-ms-'); 439 } 440 ; 441 442 /** 443 * nativeTestProps allows for us to use native feature detection functionality if available. 444 * some prefixed form, or false, in the case of an unsupported rule 445 * 446 * @access private 447 * @function nativeTestProps 448 * @param {array} props - An array of property names 449 * @param {string} value - A string representing the value we want to check via @supports 450 * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise 451 */ 452 453 // Accepts a list of property names and a single value 454 // Returns `undefined` if native detection not available 455 function nativeTestProps(props, value) { 456 var i = props.length; 457 // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface 458 if ('CSS' in window && 'supports' in window.CSS) { 459 // Try every prefixed variant of the property 460 while (i--) { 461 if (window.CSS.supports(domToCSS(props[i]), value)) { 462 return true; 463 } 464 } 465 return false; 466 } 467 // Otherwise fall back to at-rule (for Opera 12.x) 468 else if ('CSSSupportsRule' in window) { 469 // Build a condition string for every prefixed variant 470 var conditionText = []; 471 while (i--) { 472 conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')'); 473 } 474 conditionText = conditionText.join(' or '); 475 return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) { 476 return getComputedStyle(node, null).position == 'absolute'; 477 }); 478 } 479 return undefined; 480 } 481 ; 482 483 /** 484 * cssToDOM takes a kebab-case string and converts it to camelCase 485 * e.g. box-sizing -> boxSizing 486 * 487 * @access private 488 * @function cssToDOM 489 * @param {string} name - String name of kebab-case prop we want to convert 490 * @returns {string} The camelCase version of the supplied name 491 */ 492 493 function cssToDOM(name) { 494 return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) { 495 return m1 + m2.toUpperCase(); 496 }).replace(/^-/, ''); 497 } 498 ; 499 500 // testProps is a generic CSS / DOM property test. 501 502 // In testing support for a given CSS property, it's legit to test: 503 // `elem.style[styleName] !== undefined` 504 // If the property is supported it will return an empty string, 505 // if unsupported it will return undefined. 506 507 // We'll take advantage of this quick test and skip setting a style 508 // on our modernizr element, but instead just testing undefined vs 509 // empty string. 510 511 // Property names can be provided in either camelCase or kebab-case. 512 513 function testProps(props, prefixed, value, skipValueTest) { 514 skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest; 515 516 // Try native detect first 517 if (!is(value, 'undefined')) { 518 var result = nativeTestProps(props, value); 519 if (!is(result, 'undefined')) { 520 return result; 521 } 522 } 523 524 // Otherwise do it properly 525 var afterInit, i, propsLength, prop, before; 526 527 // If we don't have a style element, that means we're running async or after 528 // the core tests, so we'll need to create our own elements to use 529 530 // inside of an SVG element, in certain browsers, the `style` element is only 531 // defined for valid tags. Therefore, if `modernizr` does not have one, we 532 // fall back to a less used element and hope for the best. 533 var elems = ['modernizr', 'tspan']; 534 while (!mStyle.style) { 535 afterInit = true; 536 mStyle.modElem = createElement(elems.shift()); 537 mStyle.style = mStyle.modElem.style; 538 } 539 540 // Delete the objects if we created them. 541 function cleanElems() { 542 if (afterInit) { 543 delete mStyle.style; 544 delete mStyle.modElem; 545 } 546 } 547 548 propsLength = props.length; 549 for (i = 0; i < propsLength; i++) { 550 prop = props[i]; 551 before = mStyle.style[prop]; 552 553 if (contains(prop, '-')) { 554 prop = cssToDOM(prop); 555 } 556 557 if (mStyle.style[prop] !== undefined) { 558 559 // If value to test has been passed in, do a set-and-check test. 560 // 0 (integer) is a valid property value, so check that `value` isn't 561 // undefined, rather than just checking it's truthy. 562 if (!skipValueTest && !is(value, 'undefined')) { 563 564 // Needs a try catch block because of old IE. This is slow, but will 565 // be avoided in most cases because `skipValueTest` will be used. 566 try { 567 mStyle.style[prop] = value; 568 } catch (e) {} 569 570 // If the property value has changed, we assume the value used is 571 // supported. If `value` is empty string, it'll fail here (because 572 // it hasn't changed), which matches how browsers have implemented 573 // CSS.supports() 574 if (mStyle.style[prop] != before) { 575 cleanElems(); 576 return prefixed == 'pfx' ? prop : true; 577 } 578 } 579 // Otherwise just return true, or the property name if this is a 580 // `prefixed()` call 581 else { 582 cleanElems(); 583 return prefixed == 'pfx' ? prop : true; 584 } 585 } 586 } 587 cleanElems(); 588 return false;
589 } 590 591 ; 592 593 /** 594 * List of JavaScript DOM values used for tests 595 * 596 * @memberof Modernizr 597 * @name Modernizr._domPrefixes 598 * @optionName Modernizr._domPrefixes 599 * @optionProp domPrefixes 600 * @access public 601 * @example 602 * 603 * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather 604 * than kebab-case properties, all properties are their Capitalized variant 605 * 606 * ```js 607 * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ]; 608 * ``` 609 */ 610 611 var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []); 612 ModernizrProto._domPrefixes = domPrefixes; 613 614 615 /** 616 * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill. 617 * 618 * @access private 619 * @function fnBind 620 * @param {function} fn - a function you want to change `this` reference to 621 * @param {object} that - the `this` you want to call the function with 622 * @returns {function} The wrapped version of the supplied function 623 */ 624 625 function fnBind(fn, that) { 626 return function() { 627 return fn.apply(that, arguments); 628 }; 629 } 630 631 ; 632 633 /** 634 * testDOMProps is a generic DOM property test; if a browser supports 635 * a certain property, it won't return undefined for it. 636 * 637 * @access private 638 * @function testDOMProps 639 * @param {array.<string>} props - An array of properties to test for 640 * @param {object} obj - An object or Element you want to use to test the parameters again 641 * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check 642 */ 643 function testDOMProps(props, obj, elem) { 644 var item; 645 646 for (var i in props) { 647 if (props[i] in obj) { 648 649 // return the property name as a string 650 if (elem === false) { 651 return props[i]; 652 } 653 654 item = obj[props[i]]; 655 656 // let's bind a function 657 if (is(item, 'function')) { 658 // bind to obj unless overriden 659 return fnBind(item, elem || obj); 660 } 661 662 // return the unbound function or obj or value 663 return item; 664 } 665 } 666 return false; 667 } 668 669 ; 670 671 /** 672 * testPropsAll tests a list of DOM properties we want to check against. 673 * We specify literally ALL possible (known and/or likely) properties on 674 * the element including the non-vendor prefixed one, for forward- 675 * compatibility. 676 * 677 * @access private 678 * @function testPropsAll 679 * @param {string} prop - A string of the property to test for 680 * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip 681 * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against 682 * @param {string} [value] - A string of a css value 683 * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set 684 */ 685 function testPropsAll(prop, prefixed, elem, value, skipValueTest) { 686 687 var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), 688 props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); 689 690 // did they call .prefixed('boxSizing') or are we just testing a prop? 691 if (is(prefixed, 'string') || is(prefixed, 'undefined')) { 692 return testProps(props, prefixed, value, skipValueTest); 693 694 // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) 695 } else { 696 props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); 697 return testDOMProps(props, prefixed, elem); 698 } 699 } 700 701 // Modernizr.testAllProps() investigates whether a given style property, 702 // or any of its vendor-prefixed variants, is recognized 703 // 704 // Note that the property names must be provided in the camelCase variant. 705 // Modernizr.testAllProps('boxSizing') 706 ModernizrProto.testAllProps = testPropsAll; 707 708 709 710 /** 711 * testAllProps determines whether a given CSS property is supported in the browser 712 * 713 * @memberof Modernizr 714 * @name Modernizr.testAllProps 715 * @optionName Modernizr.testAllProps() 716 * @optionProp testAllProps 717 * @access public 718 * @function testAllProps 719 * @param {string} prop - String naming the property to test (either camelCase or kebab-case) 720 * @param {string} [value] - String of the value to test 721 * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection 722 * @example 723 * 724 * testAllProps determines whether a given CSS property, in some prefixed form, 725 * is supported by the browser. 726 * 727 * ```js 728 * testAllProps('boxSizing') // true 729 * ``` 730 * 731 * It can optionally be given a CSS value in string form to test if a property 732 * value is valid 733 * 734 * ```js 735 * testAllProps('display', 'block') // true 736 * testAllProps('display', 'penguin') // false 737 * ``` 738 * 739 * A boolean can be passed as a third parameter to skip the value check when 740 * native detection (@supports) isn't available. 741 * 742 * ```js 743 * testAllProps('shapeOutside', 'content-box', true); 744 * ``` 745 */ 746 747 function testAllProps(prop, value, skipValueTest) { 748 return testPropsAll(prop, undefined, undefined, value, skipValueTest); 749 } 750 ModernizrProto.testAllProps = testAllProps; 751 752 753 /** 754 * testStyles injects an element with style element and some CSS rules 755 * 756 * @memberof Modernizr 757 * @name Modernizr.testStyles 758 * @optionName Modernizr.testStyles() 759 * @optionProp testStyles 760 * @access public 761 * @function testStyles 762 * @param {string} rule - String representing a css rule 763 * @param {function} callback - A function that is used to test the injected element 764 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 765 * @param {string[]}
765 [testnames] - An array of strings that are used as ids for the additional nodes 766 * @returns {boolean} 767 * @example 768 * 769 * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page 770 * along with (possibly multiple) DOM elements. This lets you check for features 771 * that can not be detected by simply checking the [IDL](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Interface_development_guide/IDL_interface_rules). 772 * 773 * ```js 774 * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) { 775 * // elem is the first DOM node in the page (by default #modernizr) 776 * // rule is the first argument you supplied - the CSS rule in string form 777 * 778 * addTest('widthworks', elem.style.width === '9px') 779 * }); 780 * ``` 781 * 782 * If your test requires multiple nodes, you can include a third argument 783 * indicating how many additional div elements to include on the page. The 784 * additional nodes are injected as children of the `elem` that is returned as 785 * the first argument to the callback. 786 * 787 * ```js 788 * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) { 789 * document.getElementById('modernizr').style.width === '1px'; // true 790 * document.getElementById('modernizr2').style.width === '2px'; // true 791 * elem.firstChild === document.getElementById('modernizr2'); // true 792 * }, 1); 793 * ``` 794 * 795 * By default, all of the additional elements have an ID of `modernizr[n]`, where 796 * `n` is its index (e.g. the first additional, second overall is `#modernizr2`, 797 * the second additional is `#modernizr3`, etc.). 798 * If you want to have more meaningful IDs for your function, you can provide 799 * them as the fourth argument, as an array of strings 800 * 801 * ```js 802 * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) { 803 * elem.firstChild === document.getElementById('foo'); // true 804 * elem.lastChild === document.getElementById('bar'); // true 805 * }, 2, ['foo', 'bar']); 806 * ``` 807 * 808 */ 809 810 var testStyles = ModernizrProto.testStyles = injectElementWithStyles; 811 812/*! 813{ 814 "name": "CSS Supports", 815 "property": "supports", 816 "caniuse": "css-featurequeries", 817 "tags": ["css"], 818 "builderAliases": ["css_supports"], 819 "notes": [{ 820 "name": "W3 Spec", 821 "href": "http://dev.w3.org/csswg/css3-conditional/#at-supports" 822 },{ 823 "name": "Related Github Issue", 824 "href": "github.com/Modernizr/Modernizr/issues/648" 825 },{ 826 "name": "W3 Info", 827 "href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface" 828 }] 829} 830!*/ 831 832 var newSyntax = 'CSS' in window && 'supports' in window.CSS; 833 var oldSyntax = 'supportsCSS' in window; 834 Modernizr.addTest('supports', newSyntax || oldSyntax); 835 836/*! 837{ 838 "name": "CSS Transforms 3D", 839 "property": "csstransforms3d", 840 "caniuse": "transforms3d", 841 "tags": ["css"], 842 "warnings": [ 843 "Chrome may occassionally fail this test on some systems; more info: https://code.google.com/p/chromium/issues/detail?id=129004" 844 ] 845} 846!*/ 847 848 Modernizr.addTest('csstransforms3d', function() { 849 var ret = !!testAllProps('perspective', '1px', true); 850 var usePrefix = Modernizr._config.usePrefixes; 851 852 // Webkit's 3D transforms are passed off to the browser's own graphics renderer. 853 // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in 854 // some conditions. As a result, Webkit typically recognizes the syntax but 855 // will sometimes throw a false positive, thus we must do a more thorough check: 856 if (ret && (!usePrefix || 'webkitPerspective' in docElement.style)) { 857 var mq; 858 var defaultStyle = '#modernizr{width:0;height:0}'; 859 // Use CSS Conditional Rules if available 860 if (Modernizr.supports) { 861 mq = '@supports (perspective: 1px)'; 862 } else { 863 // Otherwise, Webkit allows this media query to succeed only if the feature is enabled. 864 // `@media (transform-3d),(-webkit-transform-3d){ ... }` 865 mq = '@media (transform-3d)'; 866 if (usePrefix) { 867 mq += ',(-webkit-transform-3d)'; 868 } 869 } 870 871 mq += '{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}'; 872 873 testStyles(defaultStyle + mq, function(elem) { 874 ret = elem.offsetWidth === 7 && elem.offsetHeight === 18; 875 }); 876 } 877 878 return ret; 879 }); 880 881 882 // Run each test 883 testRunner(); 884 885 // Remove the "no-js" class if it exists 886 setClasses(classes); 887 888 delete ModernizrProto.addTest; 889 delete ModernizrProto.addAsyncTest; 890 891 // Run the things that are supposed to run after the tests 892 for (var i = 0; i < Modernizr._q.length; i++) { 893 Modernizr._q[i](); 894 } 895 896 // Leak Modernizr namespace 897 window.Modernizr = Modernizr; 898 899 900; 901 902})(window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.