2025-10-08 10:35:48 +02:00
// NOTE: This file has been modified to set `usePrefixes: false`!
// Find-replace: %s:/\*!:/*:g
/ *
* modernizr v3 . 6.0
* Build https : //modernizr.com/download?-classlist-cssanimations-csspointerevents-cssremunit-csstransforms-customelements-customevent-documentfragment-eventlistener-history-matchmedia-opacity-promises-queryselector-requestanimationframe-template-touchevents-dontmin
*
* Copyright ( c )
* Faruk Ates
* Paul Irish
* Alex Sexton
* Ryan Seddon
* Patrick Kettner
* Stu Cox
* Richard Herrera
* MIT License
* /
/ *
* Modernizr tests which native CSS3 and HTML5 features are available in the
* current UA and makes the results available to you in two ways : as properties on
* a global ` Modernizr ` object , and as classes on the ` <html> ` element . This
* information allows you to progressively enhance your pages with a granular level
* of control over the experience .
2025-10-10 16:43:21 +02:00
* /
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
( function ( window , document , undefined ) {
var tests = [ ] ;
/ * *
*
* ModernizrProto is the constructor for Modernizr
*
* @ class
* @ access public
* /
var ModernizrProto = {
// The current version, dummy
_version : "3.6.0" ,
// Any settings that don't work as separate modules
// can go in here as configuration.
_config : {
classPrefix : "" ,
enableClasses : true ,
enableJSClass : true ,
usePrefixes : false ,
} ,
// Queue of tests
_q : [ ] ,
// Stub these for people who are listening
on : function ( test , cb ) {
// I don't really think people should do this, but we can
// safe guard it a bit.
// -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
// This is in case people listen to synchronous tests. I would leave it out,
// but the code to *disallow* sync tests in the real version of this
// function is actually larger than this.
var self = this ;
setTimeout ( function ( ) {
cb ( self [ test ] ) ;
} , 0 ) ;
} ,
addTest : function ( name , fn , options ) {
tests . push ( { name : name , fn : fn , options : options } ) ;
} ,
addAsyncTest : function ( fn ) {
tests . push ( { name : null , fn : fn } ) ;
} ,
} ;
// Fake some of Object.create so we can force non test results to be non "own" properties.
var Modernizr = function ( ) { } ;
Modernizr . prototype = ModernizrProto ;
// Leak modernizr globally when you `require` it rather than force it here.
// Overwrite name so constructor name is nicer :D
Modernizr = new Modernizr ( ) ;
// HACK: Manually add `customproperties`...
var supportsFn =
( window . CSS && window . CSS . supports . bind ( window . CSS ) ) || window . supportsCSS ;
Modernizr . addTest (
"customproperties" ,
! ! supportsFn && ( supportsFn ( "--f:0" ) || supportsFn ( "--f" , 0 ) ) ,
) ;
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "Custom Elements API" ,
"property" : "customelements" ,
"tags" : [ "customelements" ] ,
"polyfills" : [ "customelements" ] ,
"notes" : [ {
"name" : "Specs for Custom Elements" ,
"href" : "https://www.w3.org/TR/custom-elements/"
} ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Detects support for the Custom Elements API , to create custom html elements via js
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "customelements" , "customElements" in window ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "CustomEvent" ,
"property" : "customevent" ,
"tags" : [ "customevent" ] ,
"authors" : [ "Alberto Elias" ] ,
"notes" : [ {
"name" : "W3C DOM reference" ,
"href" : "https://www.w3.org/TR/DOM-Level-3-Events/#interface-CustomEvent"
} , {
"name" : "MDN documentation" ,
"href" : "https://developer.mozilla.org/en/docs/Web/API/CustomEvent"
} ] ,
"polyfills" : [ "eventlistener" ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Detects support for CustomEvent .
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest (
"customevent" ,
"CustomEvent" in window && typeof window . CustomEvent === "function" ,
) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "Event Listener" ,
"property" : "eventlistener" ,
"authors" : [ "Andrew Betts (@triblondon)" ] ,
"notes" : [ {
"name" : "W3C Spec" ,
"href" : "https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Registration-interfaces"
} ] ,
"polyfills" : [ "eventlistener" ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Detects native support for addEventListener
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "eventlistener" , "addEventListener" in window ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "QuerySelector" ,
"property" : "queryselector" ,
"caniuse" : "queryselector" ,
"tags" : [ "queryselector" ] ,
"authors" : [ "Andrew Betts (@triblondon)" ] ,
"notes" : [ {
"name" : "W3C Selectors reference" ,
"href" : "https://www.w3.org/TR/selectors-api/#queryselectorall"
} ] ,
"polyfills" : [ "css-selector-engine" ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Detects support for querySelector .
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest (
"queryselector" ,
"querySelector" in document && "querySelectorAll" in document ,
) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "History API" ,
"property" : "history" ,
"caniuse" : "history" ,
"tags" : [ "history" ] ,
"authors" : [ "Hay Kranen" , "Alexander Farkas" ] ,
"notes" : [ {
"name" : "W3C Spec" ,
"href" : "https://www.w3.org/TR/html51/browsers.html#the-history-interface"
} , {
"name" : "MDN documentation" ,
"href" : "https://developer.mozilla.org/en-US/docs/Web/API/window.history"
} ] ,
"polyfills" : [ "historyjs" , "html5historyapi" ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Detects support for the History API for manipulating the browser session history .
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "history" , function ( ) {
// Issue #733
// The stock browser on Android 2.2 & 2.3, and 4.0.x returns positive on history support
// Unfortunately support is really buggy and there is no clean way to detect
// these bugs, so we fall back to a user agent sniff :(
var ua = navigator . userAgent ;
// We only want Android 2 and 4.0, stock browser, and not Chrome which identifies
// itself as 'Mobile Safari' as well, nor Windows Phone (issue #1471).
if (
( ua . indexOf ( "Android 2." ) !== - 1 || ua . indexOf ( "Android 4.0" ) !== - 1 ) &&
ua . indexOf ( "Mobile Safari" ) !== - 1 &&
ua . indexOf ( "Chrome" ) === - 1 &&
ua . indexOf ( "Windows Phone" ) === - 1 &&
// Since all documents on file:// share an origin, the History apis are
// blocked there as well
location . protocol !== "file:"
) {
return false ;
}
// Return the regular check
return window . history && "pushState" in window . history ;
} ) ;
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "ES6 Promises" ,
"property" : "promises" ,
"caniuse" : "promises" ,
"polyfills" : [ "es6promises" ] ,
"authors" : [ "Krister Kari" , "Jake Archibald" ] ,
"tags" : [ "es6" ] ,
"notes" : [ {
"name" : "The ES6 promises spec" ,
"href" : "https://github.com/domenic/promises-unwrapping"
} , {
"name" : "Chromium dashboard - ES6 Promises" ,
"href" : "https://www.chromestatus.com/features/5681726336532480"
} , {
"name" : "JavaScript Promises: There and back again - HTML5 Rocks" ,
"href" : "http://www.html5rocks.com/en/tutorials/es6/promises/"
} ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Check if browser implements ECMAScript 6 Promises per specification .
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "promises" , function ( ) {
return (
"Promise" in window &&
// Some of these methods are missing from
// Firefox/Chrome experimental implementations
"resolve" in window . Promise &&
"reject" in window . Promise &&
"all" in window . Promise &&
"race" in window . Promise &&
// Older version of the spec had a resolver object
// as the arg rather than a function
( function ( ) {
var resolve ;
new window . Promise ( function ( r ) {
resolve = r ;
} ) ;
return typeof resolve === "function" ;
} ) ( )
) ;
} ) ;
/ * *
* is returns a boolean if the typeof an obj is exactly type .
*
* @ access private
* @ function is
* @ param { * } obj - A thing we want to check the type of
* @ param { string } type - A string to compare the typeof against
* @ returns { boolean }
* /
function is ( obj , type ) {
return typeof obj === type ;
}
var classes = [ ] ;
/ * *
* Run through all tests and detect their support in the current UA .
*
* @ access private
* /
function testRunner ( ) {
var featureNames ;
var feature ;
var aliasIdx ;
var result ;
var nameIdx ;
var featureName ;
var featureNameSplit ;
for ( var featureIdx in tests ) {
if ( tests . hasOwnProperty ( featureIdx ) ) {
featureNames = [ ] ;
feature = tests [ featureIdx ] ;
// run the test, throw the return value into the Modernizr,
// then based on that boolean, define an appropriate className
// and push it into an array of classes we'll join later.
//
// If there is no name, it's an 'async' test that is run,
// but not directly added to the object. That should
// be done with a post-run addTest call.
if ( feature . name ) {
featureNames . push ( feature . name . toLowerCase ( ) ) ;
if (
feature . options &&
feature . options . aliases &&
feature . options . aliases . length
) {
// Add all the aliases into the names list
for (
aliasIdx = 0 ;
aliasIdx < feature . options . aliases . length ;
aliasIdx ++
) {
featureNames . push (
feature . options . aliases [ aliasIdx ] . toLowerCase ( ) ,
) ;
}
}
}
// Run the test, or use the raw value if it's not a function
result = is ( feature . fn , "function" ) ? feature . fn ( ) : feature . fn ;
// Set each of the names on the Modernizr object
for ( nameIdx = 0 ; nameIdx < featureNames . length ; nameIdx ++ ) {
featureName = featureNames [ nameIdx ] ;
// Support dot properties as sub tests. We don't do checking to make sure
// that the implied parent tests have been added. You must call them in
// order (either in the test, or make the parent test a dependency).
//
// Cap it to TWO to make the logic simple and because who needs that kind of subtesting
// hashtag famous last words
featureNameSplit = featureName . split ( "." ) ;
if ( featureNameSplit . length === 1 ) {
Modernizr [ featureNameSplit [ 0 ] ] = result ;
} else {
// cast to a Boolean, if not one already
if (
Modernizr [ featureNameSplit [ 0 ] ] &&
! ( Modernizr [ featureNameSplit [ 0 ] ] instanceof Boolean )
) {
Modernizr [ featureNameSplit [ 0 ] ] = new Boolean (
Modernizr [ featureNameSplit [ 0 ] ] ,
) ;
}
Modernizr [ featureNameSplit [ 0 ] ] [ featureNameSplit [ 1 ] ] = result ;
}
classes . push ( ( result ? "" : "no-" ) + featureNameSplit . join ( "-" ) ) ;
}
}
}
}
/ * *
* List of property values to set for css tests . See ticket # 21
* http : //git.io/vUGl4
*
* @ memberof Modernizr
* @ name Modernizr . _prefixes
* @ optionName Modernizr . _prefixes
* @ optionProp prefixes
* @ access public
* @ example
*
* Modernizr . _prefixes is the internal list of prefixes that we test against
* inside of things like [ prefixed ] ( # modernizr - prefixed ) and [ prefixedCSS ] ( # - code - modernizr - prefixedcss ) . It is simply
* an array of kebab - case vendor prefixes you can use within your code .
*
* Some common use cases include
*
* Generating all possible prefixed version of a CSS property
* ` ` ` js
* var rule = Modernizr . _prefixes . join ( 'transform: rotate(20deg); ' ) ;
*
* rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
* ` ` `
*
* Generating all possible prefixed version of a CSS value
* ` ` ` js
* rule = 'display:' + Modernizr . _prefixes . join ( 'flex; display:' ) + 'flex' ;
*
* rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
* ` ` `
* /
// we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
// values in feature detects to continue to work
var prefixes = ModernizrProto . _config . usePrefixes
? " -webkit- -moz- -o- -ms- " . split ( " " )
: [ "" , "" ] ;
// expose these for the plugin API. Look in the source for how to join() them against your input
ModernizrProto . _prefixes = prefixes ;
/ * *
* docElement is a convenience wrapper to grab the root element of the document
*
* @ access private
* @ returns { HTMLElement | SVGElement } The root element of the document
* /
var docElement = document . documentElement ;
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "classList" ,
"caniuse" : "classlist" ,
"property" : "classlist" ,
"tags" : [ "dom" ] ,
"builderAliases" : [ "dataview_api" ] ,
"notes" : [ {
"name" : "MDN Docs" ,
"href" : "https://developer.mozilla.org/en/DOM/element.classList"
} ]
}
! * /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "classlist" , "classList" in docElement ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "Document Fragment" ,
"property" : "documentfragment" ,
"notes" : [ {
"name" : "W3C DOM Level 1 Reference" ,
"href" : "https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-B63ED1A3"
} , {
"name" : "SitePoint Reference" ,
"href" : "http://reference.sitepoint.com/javascript/DocumentFragment"
} , {
"name" : "QuirksMode Compatibility Tables" ,
"href" : "http://www.quirksmode.org/m/w3c_core.html#t112"
} ] ,
"authors" : [ "Ron Waldon (@jokeyrhyme)" ] ,
"knownBugs" : [ "false-positive on Blackberry 9500, see QuirksMode note" ] ,
"tags" : [ ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Append multiple elements to the DOM within a single insertion .
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "documentfragment" , function ( ) {
return "createDocumentFragment" in document && "appendChild" in docElement ;
} ) ;
/ * *
* A convenience helper to check if the document we are running in is an SVG document
*
* @ access private
* @ returns { boolean }
* /
var isSVG = docElement . nodeName . toLowerCase ( ) === "svg" ;
/ * *
* createElement is a convenience wrapper around document . createElement . Since we
* use createElement all over the place , this allows for ( slightly ) smaller code
* as well as abstracting away issues with creating elements in contexts other than
* HTML documents ( e . g . SVG documents ) .
*
* @ access private
* @ function createElement
* @ returns { HTMLElement | SVGElement } An HTML or SVG element
* /
function createElement ( ) {
if ( typeof document . createElement !== "function" ) {
// This is the case in IE7, where the type of createElement is "object".
// For this reason, we cannot call apply() as Object is not a Function.
return document . createElement ( arguments [ 0 ] ) ;
} else if ( isSVG ) {
return document . createElementNS . call (
document ,
"http://www.w3.org/2000/svg" ,
arguments [ 0 ] ,
) ;
} else {
return document . createElement . apply ( document , arguments ) ;
}
}
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "CSS Opacity" ,
"caniuse" : "css-opacity" ,
"property" : "opacity" ,
"tags" : [ "css" ]
}
! * /
2025-10-10 16:43:21 +02:00
// Browsers that actually have CSS Opacity implemented have done so
// according to spec, which means their return values are within the
// range of [0.0,1.0] - including the leading zero.
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "opacity" , function ( ) {
var style = createElement ( "a" ) . style ;
style . cssText = prefixes . join ( "opacity:.55;" ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
// The non-literal . in this regex is intentional:
// German Chrome returns this value as 0,55
// github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
return /^0.55$/ . test ( style . opacity ) ;
} ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "CSS Pointer Events" ,
"caniuse" : "pointer-events" ,
"property" : "csspointerevents" ,
"authors" : [ "ausi" ] ,
"tags" : [ "css" ] ,
"builderAliases" : [ "css_pointerevents" ] ,
"notes" : [
{
"name" : "MDN Docs" ,
"href" : "https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events"
} , {
"name" : "Test Project Page" ,
"href" : "https://ausi.github.com/Feature-detection-technique-for-pointer-events/"
} , {
"name" : "Test Project Wiki" ,
"href" : "https://github.com/ausi/Feature-detection-technique-for-pointer-events/wiki"
} ,
{
"name" : "Related Github Issue" ,
"href" : "https://github.com/Modernizr/Modernizr/issues/80"
}
]
}
! * /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "csspointerevents" , function ( ) {
var style = createElement ( "a" ) . style ;
style . cssText = "pointer-events:auto" ;
return style . pointerEvents === "auto" ;
} ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "CSS Font rem Units" ,
"caniuse" : "rem" ,
"authors" : [ "nsfmc" ] ,
"property" : "cssremunit" ,
"tags" : [ "css" ] ,
"builderAliases" : [ "css_remunit" ] ,
"notes" : [ {
"name" : "W3C Spec" ,
"href" : "https://www.w3.org/TR/css3-values/#relative0"
} , {
"name" : "Font Size with rem by Jonathan Snook" ,
"href" : "http://snook.ca/archives/html_and_css/font-size-with-rem"
} ]
}
! * /
2025-10-10 16:43:21 +02:00
// "The 'rem' unit ('root em') is relative to the computed
// value of the 'font-size' value of the root element."
// you can test by checking if the prop was ditched
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "cssremunit" , function ( ) {
var style = createElement ( "a" ) . style ;
try {
style . fontSize = "3rem" ;
} catch ( e ) { }
return /rem/ . test ( style . fontSize ) ;
} ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "Template Tag" ,
"property" : "template" ,
"tags" : [ "elem" ] ,
"notes" : [ {
"name" : "HTML5Rocks Article" ,
"href" : "http://www.html5rocks.com/en/tutorials/webcomponents/template/"
} , {
"name" : "W3 Spec" ,
"href" : "https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html"
} ]
}
! * /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "template" , "content" in createElement ( "template" ) ) ;
/ * *
* cssToDOM takes a kebab - case string and converts it to camelCase
* e . g . box - sizing - > boxSizing
*
* @ access private
* @ function cssToDOM
* @ param { string } name - String name of kebab - case prop we want to convert
* @ returns { string } The camelCase version of the supplied name
* /
function cssToDOM ( name ) {
return name
. replace ( /([a-z])-([a-z])/g , function ( str , m1 , m2 ) {
return m1 + m2 . toUpperCase ( ) ;
} )
. replace ( /^-/ , "" ) ;
}
/ * *
* getBody returns the body of a document , or an element that can stand in for
* the body if a real body does not exist
*
* @ access private
* @ function getBody
* @ returns { HTMLElement | SVGElement } Returns the real body of a document , or an
* artificially created element that stands in for the body
* /
function getBody ( ) {
// After page load injecting a fake body doesn't work so check if body exists
var body = document . body ;
if ( ! body ) {
// Can't use the real body create a fake one.
body = createElement ( isSVG ? "svg" : "body" ) ;
body . fake = true ;
}
return body ;
}
/ * *
* injectElementWithStyles injects an element with style element and some CSS rules
*
* @ access private
* @ function injectElementWithStyles
* @ param { string } rule - String representing a css rule
* @ param { function } callback - A function that is used to test the injected element
* @ param { number } [ nodes ] - An integer representing the number of additional nodes you want injected
* @ param { string [ ] } [ testnames ] - An array of strings that are used as ids for the additional nodes
* @ returns { boolean }
* /
function injectElementWithStyles ( rule , callback , nodes , testnames ) {
var mod = "modernizr" ;
var style ;
var ret ;
var node ;
var docOverflow ;
var div = createElement ( "div" ) ;
var body = getBody ( ) ;
if ( parseInt ( nodes , 10 ) ) {
// In order not to give false positives we create a node for each test
// This also allows the method to scale for unspecified uses
while ( nodes -- ) {
node = createElement ( "div" ) ;
node . id = testnames ? testnames [ nodes ] : mod + ( nodes + 1 ) ;
div . appendChild ( node ) ;
}
}
style = createElement ( "style" ) ;
style . type = "text/css" ;
style . id = "s" + mod ;
// 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.
// Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
( ! body . fake ? div : body ) . appendChild ( style ) ;
body . appendChild ( div ) ;
if ( style . styleSheet ) {
style . styleSheet . cssText = rule ;
} else {
style . appendChild ( document . createTextNode ( rule ) ) ;
}
div . id = mod ;
if ( body . fake ) {
//avoid crashing IE8, if background image is used
body . style . background = "" ;
//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
body . style . overflow = "hidden" ;
docOverflow = docElement . style . overflow ;
docElement . style . overflow = "hidden" ;
docElement . appendChild ( body ) ;
}
ret = callback ( div , rule ) ;
// If this is done after page load we don't want to remove the body so check if body exists
if ( body . fake ) {
body . parentNode . removeChild ( body ) ;
docElement . style . overflow = docOverflow ;
// Trigger layout so kinetic scrolling isn't disabled in iOS6+
// eslint-disable-next-line
docElement . offsetHeight ;
} else {
div . parentNode . removeChild ( div ) ;
}
return ! ! ret ;
}
/ * *
* testStyles injects an element with style element and some CSS rules
*
* @ memberof Modernizr
* @ name Modernizr . testStyles
* @ optionName Modernizr . testStyles ( )
* @ optionProp testStyles
* @ access public
* @ function testStyles
* @ param { string } rule - String representing a css rule
* @ param { function } callback - A function that is used to test the injected element
* @ param { number } [ nodes ] - An integer representing the number of additional nodes you want injected
* @ param { string [ ] } [ testnames ] - An array of strings that are used as ids for the additional nodes
* @ returns { boolean }
* @ example
*
* ` Modernizr.testStyles ` takes a CSS rule and injects it onto the current page
* along with ( possibly multiple ) DOM elements . This lets you check for features
* 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).
*
* ` ` ` js
* Modernizr . testStyles ( '#modernizr { width: 9px; color: papayawhip; }' , function ( elem , rule ) {
* // elem is the first DOM node in the page (by default #modernizr)
* // rule is the first argument you supplied - the CSS rule in string form
*
* addTest ( 'widthworks' , elem . style . width === '9px' )
* } ) ;
* ` ` `
*
* If your test requires multiple nodes , you can include a third argument
* indicating how many additional div elements to include on the page . The
* additional nodes are injected as children of the ` elem ` that is returned as
* the first argument to the callback .
*
* ` ` ` js
* Modernizr . testStyles ( '#modernizr {width: 1px}; #modernizr2 {width: 2px}' , function ( elem ) {
* document . getElementById ( 'modernizr' ) . style . width === '1px' ; // true
* document . getElementById ( 'modernizr2' ) . style . width === '2px' ; // true
* elem . firstChild === document . getElementById ( 'modernizr2' ) ; // true
* } , 1 ) ;
* ` ` `
*
* By default , all of the additional elements have an ID of ` modernizr[n] ` , where
* ` n ` is its index ( e . g . the first additional , second overall is ` #modernizr2 ` ,
* the second additional is ` #modernizr3 ` , etc . ) .
* If you want to have more meaningful IDs for your function , you can provide
* them as the fourth argument , as an array of strings
*
* ` ` ` js
* Modernizr . testStyles ( '#foo {width: 10px}; #bar {height: 20px}' , function ( elem ) {
* elem . firstChild === document . getElementById ( 'foo' ) ; // true
* elem . lastChild === document . getElementById ( 'bar' ) ; // true
* } , 2 , [ 'foo' , 'bar' ] ) ;
* ` ` `
*
* /
var testStyles = ( ModernizrProto . testStyles = injectElementWithStyles ) ;
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "Touch Events" ,
"property" : "touchevents" ,
"caniuse" : "touch" ,
"tags" : [ "media" , "attribute" ] ,
"notes" : [ {
"name" : "Touch Events spec" ,
"href" : "https://www.w3.org/TR/2013/WD-touch-events-20130124/"
} ] ,
"warnings" : [
"Indicates if the browser supports the Touch Events spec, and does not necessarily reflect a touchscreen device"
] ,
"knownBugs" : [
"False-positive on some configurations of Nokia N900" ,
"False-positive on some BlackBerry 6.0 builds – https://github.com/Modernizr/Modernizr/issues/372#issuecomment-3112695"
]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Indicates if the browser supports the W3C Touch Events API .
This * does not * necessarily reflect a touchscreen device :
* Older touchscreen devices only emulate mouse events
* Modern IE touch devices implement the Pointer Events API instead : use ` Modernizr.pointerevents ` to detect support for that
* Some browsers & OS setups may enable touch APIs when no touchscreen is connected
* Future browsers may implement other event models for touch interactions
See this article : [ You Can ' t Detect A Touchscreen ] ( http : //www.stucox.com/blog/you-cant-detect-a-touchscreen/).
It ' s recommended to bind both mouse and touch / pointer events simultaneously – see [ this HTML5 Rocks tutorial ] ( http : //www.html5rocks.com/en/mobile/touchandmouse/).
This test will also return ` true ` for Firefox 4 Multitouch support .
* /
2025-10-10 16:43:21 +02:00
// Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415
Modernizr . addTest ( "touchevents" , function ( ) {
var bool ;
if (
"ontouchstart" in window ||
( window . DocumentTouch && document instanceof DocumentTouch )
) {
bool = true ;
} else {
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = [
"@media (" ,
prefixes . join ( "touch-enabled),(" ) ,
"heartz" ,
")" ,
"{#modernizr{top:9px;position:absolute}}" ,
] . join ( "" ) ;
testStyles ( query , function ( node ) {
bool = node . offsetTop === 9 ;
} ) ;
}
return bool ;
} ) ;
/ * *
* contains checks to see if a string contains another string
*
* @ access private
* @ function contains
* @ param { string } str - The string we want to check for substrings
* @ param { string } substr - The substring we want to search the first string for
* @ returns { boolean }
* /
function contains ( str , substr ) {
return ! ! ~ ( "" + str ) . indexOf ( substr ) ;
}
/ * *
2025-10-08 10:35:48 +02:00
* If the browsers follow the spec , then they would expose vendor - specific styles as :
* elem . style . WebkitBorderRadius
* instead of something like the following ( which is technically incorrect ) :
* elem . style . webkitBorderRadius
* WebKit ghosts their properties in lowercase but Opera & Moz do not .
* Microsoft uses a lowercase ` ms ` instead of the correct ` Ms ` in IE8 +
* erik . eae . net / archives / 2008 / 03 / 10 / 21.48 . 10 /
* More here : github . com / Modernizr / Modernizr / issues / issue / 21
*
* @ access private
* @ returns { string } The string representing the vendor - specific style properties
* /
2025-10-10 16:43:21 +02:00
var omPrefixes = "Moz O ms Webkit" ;
var cssomPrefixes = ModernizrProto . _config . usePrefixes
? omPrefixes . split ( " " )
: [ ] ;
ModernizrProto . _cssomPrefixes = cssomPrefixes ;
/ * *
* atRule returns a given CSS property at - rule ( eg @ keyframes ) , possibly in
* some prefixed form , or false , in the case of an unsupported rule
*
* @ memberof Modernizr
* @ name Modernizr . atRule
* @ optionName Modernizr . atRule ( )
* @ optionProp atRule
* @ access public
* @ function atRule
* @ param { string } prop - String name of the @ - rule to test for
* @ returns { string | boolean } The string representing the ( possibly prefixed )
* valid version of the @ - rule , or ` false ` when it is unsupported .
* @ example
* ` ` ` js
* var keyframes = Modernizr . atRule ( '@keyframes' ) ;
*
* if ( keyframes ) {
* // keyframes are supported
* // could be `@-webkit-keyframes` or `@keyframes`
* } else {
* // keyframes === `false`
* }
* ` ` `
*
* /
var atRule = function ( prop ) {
var length = prefixes . length ;
var cssrule = window . CSSRule ;
var rule ;
if ( typeof cssrule === "undefined" ) {
return undefined ;
}
if ( ! prop ) {
return false ;
}
// remove literal @ from beginning of provided property
prop = prop . replace ( /^@/ , "" ) ;
// CSSRules use underscores instead of dashes
rule = prop . replace ( /-/g , "_" ) . toUpperCase ( ) + "_RULE" ;
if ( rule in cssrule ) {
return "@" + prop ;
}
for ( var i = 0 ; i < length ; i ++ ) {
// prefixes gives us something like -o-, and we want O_
var prefix = prefixes [ i ] ;
var thisRule = prefix . toUpperCase ( ) + "_" + rule ;
if ( thisRule in cssrule ) {
return "@-" + prefix . toLowerCase ( ) + "-" + prop ;
}
}
return false ;
} ;
ModernizrProto . atRule = atRule ;
/ * *
* List of JavaScript DOM values used for tests
*
* @ memberof Modernizr
* @ name Modernizr . _domPrefixes
* @ optionName Modernizr . _domPrefixes
* @ optionProp domPrefixes
* @ access public
* @ example
*
* Modernizr . _domPrefixes is exactly the same as [ _prefixes ] ( # modernizr - _prefixes ) , but rather
* than kebab - case properties , all properties are their Capitalized variant
*
* ` ` ` js
* Modernizr . _domPrefixes === [ "Moz" , "O" , "ms" , "Webkit" ] ;
* ` ` `
* /
var domPrefixes = ModernizrProto . _config . usePrefixes
? omPrefixes . toLowerCase ( ) . split ( " " )
: [ ] ;
ModernizrProto . _domPrefixes = domPrefixes ;
/ * *
* fnBind is a super small [ bind ] ( https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
*
* @ access private
* @ function fnBind
* @ param { function } fn - a function you want to change ` this ` reference to
* @ param { object } that - the ` this ` you want to call the function with
* @ returns { function } The wrapped version of the supplied function
* /
function fnBind ( fn , that ) {
return function ( ) {
return fn . apply ( that , arguments ) ;
} ;
}
/ * *
* testDOMProps is a generic DOM property test ; if a browser supports
* a certain property , it won ' t return undefined for it .
*
* @ access private
* @ function testDOMProps
* @ param { array . < string > } props - An array of properties to test for
* @ param { object } obj - An object or Element you want to use to test the parameters again
* @ param { boolean | object } elem - An Element to bind the property lookup again . Use ` false ` to prevent the check
* @ returns { false | * } returns false if the prop is unsupported , otherwise the value that is supported
* /
function testDOMProps ( props , obj , elem ) {
var item ;
for ( var i in props ) {
if ( props [ i ] in obj ) {
// return the property name as a string
if ( elem === false ) {
return props [ i ] ;
}
item = obj [ props [ i ] ] ;
// let's bind a function
if ( is ( item , "function" ) ) {
// bind to obj unless overriden
return fnBind ( item , elem || obj ) ;
}
// return the unbound function or obj or value
return item ;
}
}
return false ;
}
/ * *
* domToCSS takes a camelCase string and converts it to kebab - case
* e . g . boxSizing - > box - sizing
*
* @ access private
* @ function domToCSS
* @ param { string } name - String name of camelCase prop we want to convert
* @ returns { string } The kebab - case version of the supplied name
* /
function domToCSS ( name ) {
return name
. replace ( /([A-Z])/g , function ( str , m1 ) {
return "-" + m1 . toLowerCase ( ) ;
} )
. replace ( /^ms-/ , "-ms-" ) ;
}
/ * *
* wrapper around getComputedStyle , to fix issues with Firefox returning null when
* called inside of a hidden iframe
*
* @ access private
* @ function computedStyle
* @ param { HTMLElement | SVGElement } - The element we want to find the computed styles of
* @ param { string | null } [ pseudoSelector ] - An optional pseudo element selector ( e . g . : before ) , of null if none
* @ returns { CSSStyleDeclaration }
* /
function computedStyle ( elem , pseudo , prop ) {
var result ;
if ( "getComputedStyle" in window ) {
result = getComputedStyle . call ( window , elem , pseudo ) ;
var console = window . console ;
if ( result !== null ) {
if ( prop ) {
result = result . getPropertyValue ( prop ) ;
}
} else {
if ( console ) {
var method = console . error ? "error" : "log" ;
console [ method ] . call (
console ,
"getComputedStyle returning null, its possible modernizr test results are inaccurate" ,
) ;
}
}
} else {
result = ! pseudo && elem . currentStyle && elem . currentStyle [ prop ] ;
}
return result ;
}
/ * *
* nativeTestProps allows for us to use native feature detection functionality if available .
* some prefixed form , or false , in the case of an unsupported rule
*
* @ access private
* @ function nativeTestProps
* @ param { array } props - An array of property names
* @ param { string } value - A string representing the value we want to check via @ supports
* @ returns { boolean | undefined } A boolean when @ supports exists , undefined otherwise
* /
// Accepts a list of property names and a single value
// Returns `undefined` if native detection not available
function nativeTestProps ( props , value ) {
var i = props . length ;
// Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
if ( "CSS" in window && "supports" in window . CSS ) {
// Try every prefixed variant of the property
while ( i -- ) {
if ( window . CSS . supports ( domToCSS ( props [ i ] ) , value ) ) {
return true ;
}
}
return false ;
}
// Otherwise fall back to at-rule (for Opera 12.x)
else if ( "CSSSupportsRule" in window ) {
// Build a condition string for every prefixed variant
var conditionText = [ ] ;
while ( i -- ) {
conditionText . push ( "(" + domToCSS ( props [ i ] ) + ":" + value + ")" ) ;
}
conditionText = conditionText . join ( " or " ) ;
return injectElementWithStyles (
"@supports (" +
conditionText +
") { #modernizr { position: absolute; } }" ,
function ( node ) {
return computedStyle ( node , null , "position" ) == "absolute" ;
} ,
) ;
}
return undefined ;
}
/ * *
* Create our "modernizr" element that we do most feature tests on .
*
* @ access private
* /
var modElem = {
elem : createElement ( "modernizr" ) ,
} ;
// Clean up this element
Modernizr . _q . push ( function ( ) {
delete modElem . elem ;
} ) ;
var mStyle = {
style : modElem . elem . style ,
} ;
// kill ref for gc, must happen before mod.elem is removed, so we unshift on to
// the front of the queue.
Modernizr . _q . unshift ( function ( ) {
delete mStyle . style ;
} ) ;
// testProps is a generic CSS / DOM property test.
// In testing support for a given CSS property, it's legit to test:
// `elem.style[styleName] !== undefined`
// If the property is supported it will return an empty string,
// if unsupported it will return undefined.
// We'll take advantage of this quick test and skip setting a style
// on our modernizr element, but instead just testing undefined vs
// empty string.
// Property names can be provided in either camelCase or kebab-case.
function testProps ( props , prefixed , value , skipValueTest ) {
skipValueTest = is ( skipValueTest , "undefined" ) ? false : skipValueTest ;
// Try native detect first
if ( ! is ( value , "undefined" ) ) {
var result = nativeTestProps ( props , value ) ;
if ( ! is ( result , "undefined" ) ) {
return result ;
}
}
// Otherwise do it properly
var afterInit , i , propsLength , prop , before ;
// If we don't have a style element, that means we're running async or after
// the core tests, so we'll need to create our own elements to use
// inside of an SVG element, in certain browsers, the `style` element is only
// defined for valid tags. Therefore, if `modernizr` does not have one, we
// fall back to a less used element and hope for the best.
// for strict XHTML browsers the hardly used samp element is used
var elems = [ "modernizr" , "tspan" , "samp" ] ;
while ( ! mStyle . style && elems . length ) {
afterInit = true ;
mStyle . modElem = createElement ( elems . shift ( ) ) ;
mStyle . style = mStyle . modElem . style ;
}
// Delete the objects if we created them.
function cleanElems ( ) {
if ( afterInit ) {
delete mStyle . style ;
delete mStyle . modElem ;
}
}
propsLength = props . length ;
for ( i = 0 ; i < propsLength ; i ++ ) {
prop = props [ i ] ;
before = mStyle . style [ prop ] ;
if ( contains ( prop , "-" ) ) {
prop = cssToDOM ( prop ) ;
}
if ( mStyle . style [ prop ] !== undefined ) {
// If value to test has been passed in, do a set-and-check test.
// 0 (integer) is a valid property value, so check that `value` isn't
// undefined, rather than just checking it's truthy.
if ( ! skipValueTest && ! is ( value , "undefined" ) ) {
// Needs a try catch block because of old IE. This is slow, but will
// be avoided in most cases because `skipValueTest` will be used.
try {
mStyle . style [ prop ] = value ;
} catch ( e ) { }
// If the property value has changed, we assume the value used is
// supported. If `value` is empty string, it'll fail here (because
// it hasn't changed), which matches how browsers have implemented
// CSS.supports()
if ( mStyle . style [ prop ] != before ) {
cleanElems ( ) ;
return prefixed == "pfx" ? prop : true ;
}
}
// Otherwise just return true, or the property name if this is a
// `prefixed()` call
else {
cleanElems ( ) ;
return prefixed == "pfx" ? prop : true ;
}
}
}
cleanElems ( ) ;
return false ;
}
/ * *
* testPropsAll tests a list of DOM properties we want to check against .
* We specify literally ALL possible ( known and / or likely ) properties on
* the element including the non - vendor prefixed one , for forward -
* compatibility .
*
* @ access private
* @ function testPropsAll
* @ param { string } prop - A string of the property to test for
* @ param { string | object } [ prefixed ] - An object to check the prefixed properties on . Use a string to skip
* @ param { HTMLElement | SVGElement } [ elem ] - An element used to test the property and value against
* @ param { string } [ value ] - A string of a css value
* @ param { boolean } [ skipValueTest ] - An boolean representing if you want to test if value sticks when set
* @ returns { false | string } returns the string version of the property , or false if it is unsupported
* /
function testPropsAll ( prop , prefixed , elem , value , skipValueTest ) {
var ucProp = prop . charAt ( 0 ) . toUpperCase ( ) + prop . slice ( 1 ) ,
props = ( prop + " " + cssomPrefixes . join ( ucProp + " " ) + ucProp ) . split (
" " ,
) ;
// did they call .prefixed('boxSizing') or are we just testing a prop?
if ( is ( prefixed , "string" ) || is ( prefixed , "undefined" ) ) {
return testProps ( props , prefixed , value , skipValueTest ) ;
// otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
} else {
props = ( prop + " " + domPrefixes . join ( ucProp + " " ) + ucProp ) . split ( " " ) ;
return testDOMProps ( props , prefixed , elem ) ;
}
}
// Modernizr.testAllProps() investigates whether a given style property,
// or any of its vendor-prefixed variants, is recognized
//
// Note that the property names must be provided in the camelCase variant.
// Modernizr.testAllProps('boxSizing')
ModernizrProto . testAllProps = testPropsAll ;
/ * *
* testAllProps determines whether a given CSS property is supported in the browser
*
* @ memberof Modernizr
* @ name Modernizr . testAllProps
* @ optionName Modernizr . testAllProps ( )
* @ optionProp testAllProps
* @ access public
* @ function testAllProps
* @ param { string } prop - String naming the property to test ( either camelCase or kebab - case )
* @ param { string } [ value ] - String of the value to test
* @ param { boolean } [ skipValueTest = false ] - Whether to skip testing that the value is supported when using non - native detection
* @ example
*
* testAllProps determines whether a given CSS property , in some prefixed form ,
* is supported by the browser .
*
* ` ` ` js
* testAllProps ( 'boxSizing' ) // true
* ` ` `
*
* It can optionally be given a CSS value in string form to test if a property
* value is valid
*
* ` ` ` js
* testAllProps ( 'display' , 'block' ) // true
* testAllProps ( 'display' , 'penguin' ) // false
* ` ` `
*
* A boolean can be passed as a third parameter to skip the value check when
* native detection ( @ supports ) isn ' t available .
*
* ` ` ` js
* testAllProps ( 'shapeOutside' , 'content-box' , true ) ;
* ` ` `
* /
function testAllProps ( prop , value , skipValueTest ) {
return testPropsAll ( prop , undefined , undefined , value , skipValueTest ) ;
}
ModernizrProto . testAllProps = testAllProps ;
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "CSS Animations" ,
"property" : "cssanimations" ,
"caniuse" : "css-animation" ,
"polyfills" : [ "transformie" , "csssandpaper" ] ,
"tags" : [ "css" ] ,
"warnings" : [ "Android < 4 will pass this test, but can only animate a single property at a time" ] ,
"notes" : [ {
"name" : "Article: 'Dispelling the Android CSS animation myths'" ,
"href" : "https://goo.gl/OGw5Gm"
} ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Detects whether or not elements can be animated using CSS
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "cssanimations" , testAllProps ( "animationName" , "a" , true ) ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "CSS Transforms" ,
"property" : "csstransforms" ,
"caniuse" : "transforms2d" ,
"tags" : [ "css" ]
}
! * /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "csstransforms" , function ( ) {
// Android < 3.0 is buggy, so we sniff and blacklist
// http://git.io/hHzL7w
return (
navigator . userAgent . indexOf ( "Android 2." ) === - 1 &&
testAllProps ( "transform" , "scale(1)" , true )
) ;
} ) ;
/ * *
* prefixed returns the prefixed or nonprefixed property name variant of your input
*
* @ memberof Modernizr
* @ name Modernizr . prefixed
* @ optionName Modernizr . prefixed ( )
* @ optionProp prefixed
* @ access public
* @ function prefixed
* @ param { string } prop - String name of the property to test for
* @ param { object } [ obj ] - An object to test for the prefixed properties on
* @ param { HTMLElement } [ elem ] - An element used to test specific properties against
* @ returns { string | false } The string representing the ( possibly prefixed ) valid
* version of the property , or ` false ` when it is unsupported .
* @ example
*
* Modernizr . prefixed takes a string css value in the DOM style camelCase ( as
* opposed to the css style kebab - case ) form and returns the ( possibly prefixed )
* version of that property that the browser actually supports .
*
* For example , in older Firefox ...
* ` ` ` js
* prefixed ( 'boxSizing' )
* ` ` `
* returns 'MozBoxSizing'
*
* In newer Firefox , as well as any other browser that support the unprefixed
* version would simply return ` boxSizing ` . Any browser that does not support
* the property at all , it will return ` false ` .
*
* By default , prefixed is checked against a DOM element . If you want to check
* for a property on another object , just pass it as a second argument
*
* ` ` ` js
* var rAF = prefixed ( 'requestAnimationFrame' , window ) ;
*
* raf ( function ( ) {
* renderFunction ( ) ;
* } )
* ` ` `
*
* Note that this will return _the actual function _ - not the name of the function .
* If you need the actual name of the property , pass in ` false ` as a third argument
*
* ` ` ` js
* var rAFProp = prefixed ( 'requestAnimationFrame' , window , false ) ;
*
* rafProp === 'WebkitRequestAnimationFrame' // in older webkit
* ` ` `
*
* One common use case for prefixed is if you ' re trying to determine which transition
* end event to bind to , you might do something like ...
* ` ` ` js
* var transEndEventNames = {
* 'WebkitTransition' : 'webkitTransitionEnd' , * Saf 6 , Android Browser
* 'MozTransition' : 'transitionend' , * only for FF < 15
* 'transition' : 'transitionend' * IE10 , Opera , Chrome , FF 15 + , Saf 7 +
* } ;
*
* var transEndEventName = transEndEventNames [ Modernizr . prefixed ( 'transition' ) ] ;
* ` ` `
*
* If you want a similar lookup , but in kebab - case , you can use [ prefixedCSS ] ( # modernizr - prefixedcss ) .
* /
var prefixed = ( ModernizrProto . prefixed = function ( prop , obj , elem ) {
if ( prop . indexOf ( "@" ) === 0 ) {
return atRule ( prop ) ;
}
if ( prop . indexOf ( "-" ) != - 1 ) {
// Convert kebab-case to camelCase
prop = cssToDOM ( prop ) ;
}
if ( ! obj ) {
return testPropsAll ( prop , "pfx" ) ;
} else {
// Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
return testPropsAll ( prop , obj , elem ) ;
}
} ) ;
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "requestAnimationFrame" ,
"property" : "requestanimationframe" ,
"aliases" : [ "raf" ] ,
"caniuse" : "requestanimationframe" ,
"tags" : [ "animation" ] ,
"authors" : [ "Addy Osmani" ] ,
"notes" : [ {
"name" : "W3C spec" ,
"href" : "https://www.w3.org/TR/animation-timing/"
} ] ,
"polyfills" : [ "raf" ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Detects support for the ` window.requestAnimationFrame ` API , for offloading animation repainting to the browser for optimized performance .
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest (
"requestanimationframe" ,
! ! prefixed ( "requestAnimationFrame" , window ) ,
{ aliases : [ "raf" ] } ,
) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
/ *
2025-10-08 10:35:48 +02:00
{
"name" : "matchMedia" ,
"property" : "matchmedia" ,
"caniuse" : "matchmedia" ,
"tags" : [ "matchmedia" ] ,
"authors" : [ "Alberto Elias" ] ,
"notes" : [ {
"name" : "W3C CSSOM View Module" ,
"href" : "https://drafts.csswg.org/cssom-view/#the-mediaquerylist-interface"
} , {
"name" : "MDN documentation" ,
"href" : "https://developer.mozilla.org/en-US/docs/Web/API/Window.matchMedia"
} ] ,
"polyfills" : [ "matchmediajs" ]
}
! * /
2025-10-10 16:43:21 +02:00
/ * D O C
2025-10-08 10:35:48 +02:00
Detects support for matchMedia .
* /
2025-10-10 16:43:21 +02:00
Modernizr . addTest ( "matchmedia" , ! ! prefixed ( "matchMedia" , window ) ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
// Run each test
testRunner ( ) ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
delete ModernizrProto . addTest ;
delete ModernizrProto . addAsyncTest ;
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
// Run the things that are supposed to run after the tests
for ( var i = 0 ; i < Modernizr . _q . length ; i ++ ) {
Modernizr . _q [ i ] ( ) ;
}
2025-10-08 10:35:48 +02:00
2025-10-10 16:43:21 +02:00
// Leak Modernizr namespace
window . Modernizr = Modernizr ;
} ) ( window , document ) ;