1/*! 2 * modernizr v3.5.0 3 * Build https://modernizr.com/download?-cssgrid_cssgridlegacy-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 classes = []; 27 28 29 var tests = []; 30 31 32 /** 33 * 34 * ModernizrProto is the constructor for Modernizr 35 * 36 * @class 37 * @access public 38 */ 39 40 var ModernizrProto = { 41 // The current version, dummy 42 _version: '3.5.0', 43 44 // Any settings that don't work as separate modules 45 // can go in here as configuration. 46 _config: { 47 'classPrefix': '', 48 'enableClasses': true, 49 'enableJSClass': true, 50 'usePrefixes': true 51 }, 52 53 // Queue of tests 54 _q: [], 55 56 // Stub these for people who are listening 57 on: function(test, cb) { 58 // I don't really think people should do this, but we can 59 // safe guard it a bit. 60 // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests. 61 // This is in case people listen to synchronous tests. I would leave it out, 62 // but the code to *disallow* sync tests in the real version of this 63 // function is actually larger than this. 64 var self = this; 65 setTimeout(function() { 66 cb(self[test]); 67 }, 0); 68 }, 69 70 addTest: function(name, fn, options) { 71 tests.push({name: name, fn: fn, options: options}); 72 }, 73 74 addAsyncTest: function(fn) { 75 tests.push({name: null, fn: fn}); 76 } 77 }; 78 79 80 81 // Fake some of Object.create so we can force non test results to be non "own" properties. 82 var Modernizr = function() {}; 83 Modernizr.prototype = ModernizrProto; 84 85 // Leak modernizr globally when you `require` it rather than force it here. 86 // Overwrite name so constructor name is nicer :D 87 Modernizr = new Modernizr(); 88 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 if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) { 163 Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]); 164 } 165 166 Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result; 167 } 168 169 classes.push((result ? '' : 'no-') + featureNameSplit.join('-')); 170 } 171 } 172 } 173 } 174 ; 175 176 /** 177 * docElement is a convenience wrapper to grab the root element of the document 178 * 179 * @access private 180 * @returns {HTMLElement|SVGElement} The root element of the document 181 */ 182 183 var docElement = document.documentElement; 184 185 186 /** 187 * A convenience helper to check if the document we are running in is an SVG document 188 * 189 * @access private 190 * @returns {boolean} 191 */ 192 193 var isSVG = docElement.nodeName.toLowerCase() === 'svg'; 194 195 196 /** 197 * setClasses takes an array of class names and adds them to the root element 198 * 199 * @access private 200 * @function setClasses 201 * @param {string[]} classes - Array of class names 202 */ 203 204 // Pass in an and array of class names, e.g.:
205 // ['no-webp', 'borderradius', ...] 206 function setClasses(classes) { 207 var className = docElement.className; 208 var classPrefix = Modernizr._config.classPrefix || ''; 209 210 if (isSVG) { 211 className = className.baseVal; 212 } 213 214 // Change `no-js` to `js` (independently of the `enableClasses` option) 215 // Handle classPrefix on this too 216 if (Modernizr._config.enableJSClass) { 217 var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)'); 218 className = className.replace(reJS, '$1' + classPrefix + 'js$2'); 219 } 220 221 if (Modernizr._config.enableClasses) { 222 // Add the new classes 223 className += ' ' + classPrefix + classes.join(' ' + classPrefix); 224 if (isSVG) { 225 docElement.className.baseVal = className; 226 } else { 227 docElement.className = className; 228 } 229 } 230 231 } 232 233 ; 234 235 /** 236 * If the browsers follow the spec, then they would expose vendor-specific styles as: 237 * elem.style.WebkitBorderRadius 238 * instead of something like the following (which is technically incorrect): 239 * elem.style.webkitBorderRadius 240 241 * WebKit ghosts their properties in lowercase but Opera & Moz do not. 242 * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ 243 * erik.eae.net/archives/2008/03/10/21.48.10/ 244 245 * More here: github.com/Modernizr/Modernizr/issues/issue/21 246 * 247 * @access private 248 * @returns {string} The string representing the vendor-specific style properties 249 */ 250 251 var omPrefixes = 'Moz O ms Webkit'; 252 253 254 var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []); 255 ModernizrProto._cssomPrefixes = cssomPrefixes; 256 257 258 /** 259 * List of JavaScript DOM values used for tests 260 * 261 * @memberof Modernizr 262 * @name Modernizr._domPrefixes 263 * @optionName Modernizr._domPrefixes 264 * @optionProp domPrefixes 265 * @access public 266 * @example 267 * 268 * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather 269 * than kebab-case properties, all properties are their Capitalized variant 270 * 271 * ```js 272 * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ]; 273 * ``` 274 */ 275 276 var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []); 277 ModernizrProto._domPrefixes = domPrefixes; 278 279 280 281 /** 282 * contains checks to see if a string contains another string 283 * 284 * @access private 285 * @function contains 286 * @param {string} str - The string we want to check for substrings 287 * @param {string} substr - The substring we want to search the first string for 288 * @returns {boolean} 289 */ 290 291 function contains(str, substr) { 292 return !!~('' + str).indexOf(substr); 293 } 294 295 ; 296 297 /** 298 * createElement is a convenience wrapper around document.createElement. Since we 299 * use createElement all over the place, this allows for (slightly) smaller code 300 * as well as abstracting away issues with creating elements in contexts other than 301 * HTML documents (e.g. SVG documents). 302 * 303 * @access private 304 * @function createElement 305 * @returns {HTMLElement|SVGElement} An HTML or SVG element 306 */ 307 308 function createElement() { 309 if (typeof document.createElement !== 'function') { 310 // This is the case in IE7, where the type of createElement is "object". 311 // For this reason, we cannot call apply() as Object is not a Function. 312 return document.createElement(arguments[0]); 313 } else if (isSVG) { 314 return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]); 315 } else { 316 return document.createElement.apply(document, arguments); 317 } 318 } 319 320 ; 321 322 /** 323 * cssToDOM takes a kebab-case string and converts it to camelCase 324 * e.g. box-sizing -> boxSizing 325 * 326 * @access private 327 * @function cssToDOM 328 * @param {string} name - String name of kebab-case prop we want to convert 329 * @returns {string} The camelCase version of the supplied name 330 */ 331 332 function cssToDOM(name) { 333 return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) { 334 return m1 + m2.toUpperCase(); 335 }).replace(/^-/, ''); 336 } 337 ; 338 339 /** 340 * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill. 341 * 342 * @access private 343 * @function fnBind 344 * @param {function} fn - a function you want to change `this` reference to 345 * @param {object} that - the `this` you want to call the function with 346 * @returns {function} The wrapped version of the supplied function 347 */ 348 349 function fnBind(fn, that) { 350 return function() { 351 return fn.apply(that, arguments); 352 }; 353 } 354 355 ; 356 357 /** 358 * testDOMProps is a generic DOM property test; if a browser supports 359 * a certain property, it won't return undefined for it. 360 * 361 * @access private 362 * @function testDOMProps 363 * @param {array.<string>} props - An array of properties to test for 364 * @param {object} obj - An object or Element you want to use to test the parameters again 365 * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check 366 * @returns {false|*} returns false if the prop is unsupported, otherwise the value that is supported 367 */ 368 function testDOMProps(props, obj, elem) { 369 var item; 370 371 for (var i in props) { 372 if (props[i] in obj) { 373 374 // return the property name as a string 375 if (elem === false) { 376 return props[i]; 377 } 378 379 item = obj[props[i]]; 380 381 // let's bind a function 382 if (is(item, 'function')) { 383 // bind to obj unless overriden 384 return fnBind(item, elem || obj); 385 } 386 387 // return the unbound function or obj or value 388 return item; 389 } 390 } 391 return false; 392 } 393 394 ; 395 396 /** 397 * Create our "modernizr" element that we do most feature tests on. 398 * 399 * @access private 400 */ 401 402 var modElem = { 403 elem: createElement('modernizr') 404 }; 405 406 // Clean up this element 407 Modernizr._q.push(function() { 408 delete modElem.elem; 409 }); 410 411 412 413 var mStyle = { 414 style: modElem.elem.style 415 }; 416 417 // kill ref for gc, must happen before mod.elem is removed, so we unshift on to 418 // the front of the queue. 419 Modernizr._q.unshift(function() { 420 delete mStyle.style; 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 /** 444 * wrapper around getComputedStyle, to fix issues with Firefox returning null when
445 * called inside of a hidden iframe 446 * 447 * @access private 448 * @function computedStyle 449 * @param {HTMLElement|SVGElement} - The element we want to find the computed styles of 450 * @param {string|null} [pseudoSelector]- An optional pseudo element selector (e.g. :before), of null if none 451 * @returns {CSSStyleDeclaration} 452 */ 453 454 function computedStyle(elem, pseudo, prop) { 455 var result; 456 457 if ('getComputedStyle' in window) { 458 result = getComputedStyle.call(window, elem, pseudo); 459 var console = window.console; 460 461 if (result !== null) { 462 if (prop) { 463 result = result.getPropertyValue(prop); 464 } 465 } else { 466 if (console) { 467 var method = console.error ? 'error' : 'log'; 468 console[method].call(console, 'getComputedStyle returning null, its possible modernizr test results are inaccurate'); 469 } 470 } 471 } else { 472 result = !pseudo && elem.currentStyle && elem.currentStyle[prop]; 473 } 474 475 return result; 476 } 477 478 ; 479 480 /** 481 * getBody returns the body of a document, or an element that can stand in for 482 * the body if a real body does not exist 483 * 484 * @access private 485 * @function getBody 486 * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an 487 * artificially created element that stands in for the body 488 */ 489 490 function getBody() { 491 // After page load injecting a fake body doesn't work so check if body exists 492 var body = document.body; 493 494 if (!body) { 495 // Can't use the real body create a fake one. 496 body = createElement(isSVG ? 'svg' : 'body'); 497 body.fake = true; 498 } 499 500 return body; 501 } 502 503 ; 504 505 /** 506 * injectElementWithStyles injects an element with style element and some CSS rules 507 * 508 * @access private 509 * @function injectElementWithStyles 510 * @param {string} rule - String representing a css rule 511 * @param {function} callback - A function that is used to test the injected element 512 * @param {number} [nodes] - An integer representing the number of additional nodes you want injected 513 * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes 514 * @returns {boolean} 515 */ 516 517 function injectElementWithStyles(rule, callback, nodes, testnames) { 518 var mod = 'modernizr'; 519 var style; 520 var ret; 521 var node; 522 var docOverflow; 523 var div = createElement('div'); 524 var body = getBody(); 525 526 if (parseInt(nodes, 10)) { 527 // In order not to give false positives we create a node for each test 528 // This also allows the method to scale for unspecified uses 529 while (nodes--) { 530 node = createElement('div'); 531 node.id = testnames ? testnames[nodes] : mod + (nodes + 1); 532 div.appendChild(node); 533 } 534 } 535 536 style = createElement('style'); 537 style.type = 'text/css'; 538 style.id = 's' + mod; 539 540 // 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. 541 // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270 542 (!body.fake ? div : body).appendChild(style); 543 body.appendChild(div); 544 545 if (style.styleSheet) { 546 style.styleSheet.cssText = rule; 547 } else { 548 style.appendChild(document.createTextNode(rule)); 549 } 550 div.id = mod; 551 552 if (body.fake) { 553 //avoid crashing IE8, if background image is used 554 body.style.background = ''; 555 //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible 556 body.style.overflow = 'hidden'; 557 docOverflow = docElement.style.overflow; 558 docElement.style.overflow = 'hidden'; 559 docElement.appendChild(body); 560 } 561 562 ret = callback(div, rule); 563 // If this is done after page load we don't want to remove the body so check if body exists 564 if (body.fake) { 565 body.parentNode.removeChild(body); 566 docElement.style.overflow = docOverflow; 567 // Trigger layout so kinetic scrolling isn't disabled in iOS6+ 568 // eslint-disable-next-line 569 docElement.offsetHeight; 570 } else { 571 div.parentNode.removeChild(div); 572 } 573 574 return !!ret; 575 576 } 577 578 ; 579 580 /** 581 * nativeTestProps allows for us to use native feature detection functionality if available. 582 * some prefixed form, or false, in the case of an unsupported rule 583 * 584 * @access private 585 * @function nativeTestProps 586 * @param {array} props - An array of property names 587 * @param {string} value - A string representing the value we want to check via @supports 588 * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise 589 */ 590 591 // Accepts a list of property names and a single value 592 // Returns `undefined` if native detection not available 593 function nativeTestProps(props, value) { 594 var i = props.length; 595 // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface 596 if ('CSS' in window && 'supports' in window.CSS) { 597 // Try every prefixed variant of the property 598 while (i--) { 599 if (window.CSS.supports(domToCSS(props[i]), value)) { 600 return true; 601 } 602 } 603 return false; 604 } 605 // Otherwise fall back to at-rule (for Opera 12.x) 606 else if ('CSSSupportsRule' in window) { 607 // Build a condition string for every prefixed variant 608 var conditionText = []; 609 while (i--) { 610 conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')'); 611 } 612 conditionText = conditionText.join(' or '); 613 return injectElementWithStyles('@supports (' + conditionText
613+ ') { #modernizr { position: absolute; } }', function(node) { 614 return computedStyle(node, null, 'position') == 'absolute'; 615 }); 616 } 617 return undefined; 618 } 619 ; 620 621 // testProps is a generic CSS / DOM property test. 622 623 // In testing support for a given CSS property, it's legit to test: 624 // `elem.style[styleName] !== undefined` 625 // If the property is supported it will return an empty string, 626 // if unsupported it will return undefined. 627 628 // We'll take advantage of this quick test and skip setting a style 629 // on our modernizr element, but instead just testing undefined vs 630 // empty string. 631 632 // Property names can be provided in either camelCase or kebab-case. 633 634 function testProps(props, prefixed, value, skipValueTest) { 635 skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest; 636 637 // Try native detect first 638 if (!is(value, 'undefined')) { 639 var result = nativeTestProps(props, value); 640 if (!is(result, 'undefined')) { 641 return result; 642 } 643 } 644 645 // Otherwise do it properly 646 var afterInit, i, propsLength, prop, before; 647 648 // If we don't have a style element, that means we're running async or after 649 // the core tests, so we'll need to create our own elements to use 650 651 // inside of an SVG element, in certain browsers, the `style` element is only 652 // defined for valid tags. Therefore, if `modernizr` does not have one, we 653 // fall back to a less used element and hope for the best. 654 // for strict XHTML browsers the hardly used samp element is used 655 var elems = ['modernizr', 'tspan', 'samp']; 656 while (!mStyle.style && elems.length) { 657 afterInit = true; 658 mStyle.modElem = createElement(elems.shift()); 659 mStyle.style = mStyle.modElem.style; 660 } 661 662 // Delete the objects if we created them. 663 function cleanElems() { 664 if (afterInit) { 665 delete mStyle.style; 666 delete mStyle.modElem; 667 } 668 } 669 670 propsLength = props.length; 671 for (i = 0; i < propsLength; i++) { 672 prop = props[i]; 673 before = mStyle.style[prop]; 674 675 if (contains(prop, '-')) { 676 prop = cssToDOM(prop); 677 } 678 679 if (mStyle.style[prop] !== undefined) { 680 681 // If value to test has been passed in, do a set-and-check test. 682 // 0 (integer) is a valid property value, so check that `value` isn't 683 // undefined, rather than just checking it's truthy. 684 if (!skipValueTest && !is(value, 'undefined')) { 685 686 // Needs a try catch block because of old IE. This is slow, but will 687 // be avoided in most cases because `skipValueTest` will be used. 688 try { 689 mStyle.style[prop] = value; 690 } catch (e) {} 691 692 // If the property value has changed, we assume the value used is 693 // supported. If `value` is empty string, it'll fail here (because 694 // it hasn't changed), which matches how browsers have implemented 695 // CSS.supports() 696 if (mStyle.style[prop] != before) { 697 cleanElems(); 698 return prefixed == 'pfx' ? prop : true; 699 } 700 } 701 // Otherwise just return true, or the property name if this is a 702 // `prefixed()` call 703 else { 704 cleanElems(); 705 return prefixed == 'pfx' ? prop : true; 706 } 707 } 708 } 709 cleanElems(); 710 return false; 711 } 712 713 ; 714 715 /** 716 * testPropsAll tests a list of DOM properties we want to check against. 717 * We specify literally ALL possible (known and/or likely) properties on 718 * the element including the non-vendor prefixed one, for forward- 719 * compatibility. 720 * 721 * @access private 722 * @function testPropsAll 723 * @param {string} prop - A string of the property to test for 724 * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip 725 * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against 726 * @param {string} [value] - A string of a css value 727 * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set 728 * @returns {false|string} returns the string version of the property, or false if it is unsupported 729 */ 730 function testPropsAll(prop, prefixed, elem, value, skipValueTest) { 731 732 var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
733 props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); 734 735 // did they call .prefixed('boxSizing') or are we just testing a prop? 736 if (is(prefixed, 'string') || is(prefixed, 'undefined')) { 737 return testProps(props, prefixed, value, skipValueTest); 738 739 // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) 740 } else { 741 props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); 742 return testDOMProps(props, prefixed, elem); 743 } 744 } 745 746 // Modernizr.testAllProps() investigates whether a given style property, 747 // or any of its vendor-prefixed variants, is recognized 748 // 749 // Note that the property names must be provided in the camelCase variant. 750 // Modernizr.testAllProps('boxSizing') 751 ModernizrProto.testAllProps = testPropsAll; 752 753 754 755 /** 756 * testAllProps determines whether a given CSS property is supported in the browser 757 * 758 * @memberof Modernizr 759 * @name Modernizr.testAllProps 760 * @optionName Modernizr.testAllProps() 761 * @optionProp testAllProps 762 * @access public 763 * @function testAllProps 764 * @param {string} prop - String naming the property to test (either camelCase or kebab-case) 765 * @param {string} [value] - String of the value to test 766 * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection 767 * @example 768 * 769 * testAllProps determines whether a given CSS property, in some prefixed form, 770 * is supported by the browser. 771 * 772 * ```js 773 * testAllProps('boxSizing') // true 774 * ``` 775 * 776 * It can optionally be given a CSS value in string form to test if a property 777 * value is valid 778 * 779 * ```js 780 * testAllProps('display', 'block') // true 781 * testAllProps('display', 'penguin') // false 782 * ``` 783 * 784 * A boolean can be passed as a third parameter to skip the value check when 785 * native detection (@supports) isn't available. 786 * 787 * ```js 788 * testAllProps('shapeOutside', 'content-box', true); 789 * ``` 790 */ 791 792 function testAllProps(prop, value, skipValueTest) { 793 return testPropsAll(prop, undefined, undefined, value, skipValueTest); 794 } 795 ModernizrProto.testAllProps = testAllProps; 796 797/*! 798{ 799 "name": "CSS Grid (old & new)", 800 "property": ["cssgrid", "cssgridlegacy"], 801 "authors": ["Faruk Ates"], 802 "tags": ["css"], 803 "notes": [{ 804 "name": "The new, standardized CSS Grid", 805 "href": "https://www.w3.org/TR/css3-grid-layout/" 806 }, { 807 "name": "The _old_ CSS Grid (legacy)", 808 "href": "https://www.w3.org/TR/2011/WD-css3-grid-layout-20110407/" 809 }] 810} 811!*/ 812 813 // `grid-columns` is only in the old syntax, `grid-column` exists in both and so `grid-template-rows` is used for the new syntax. 814 Modernizr.addTest('cssgridlegacy', testAllProps('grid-columns', '10px', true)); 815 Modernizr.addTest('cssgrid', testAllProps('grid-template-rows', 'none', true)); 816 817 818 // Run each test 819 testRunner(); 820 821 // Remove the "no-js" class if it exists 822 setClasses(classes); 823 824 delete ModernizrProto.addTest; 825 delete ModernizrProto.addAsyncTest; 826 827 // Run the things that are supposed to run after the tests 828 for (var i = 0; i < Modernizr._q.length; i++) { 829 Modernizr._q[i](); 830 } 831 832 // Leak Modernizr namespace 833 window.Modernizr = Modernizr; 834 835 836; 837 838})(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.