CSS media query matching in JavaScript using
window.matchMedia()
There may be times when, in addition to CSS, you also need to do something in JavaScript when a CSS media query is matched. While CSS purists may cower at the idea of mixing the two when it comes to handling media queries, at the end of the day, having JavaScript on board just means an additional tool in our "responsive" arsenal, and a very robust tool at that.
In JavaScript, you can detect for the same CSS media query string defined
in CSS with the method window.matchMedia()
. For example, in CSS,
if you have the following CSS media query:
/* #### CSS that's
applied when the viewing area's width is 765px or less #### */
@media screen and (max-width: 765px){
/* CSS definitions here */
}
To detect the same media query in JavaScript, you'd do the following:
var mql = window.matchMedia("screen and (max-width: 765px)")
Notice the query string entered in both cases is identical with the
exception of "@media
" in the former case. That's the beauty of
the JavaScript set up- it pretty much mirrors the construct of its CSS
counterpart. window.matchMedia()
returns a MediaQueryList
object containing a couple of methods and properties, the most frequently
used being the "matches
" property. It's a Boolean property that
returns true if the media query matches the state of the current window, and
false if not. More on this later.
Browser compatibility wise, window.matchMedia()
is supported
in FF6+, IE10+, Chrome/ Safari, and Opera 12+. To test for browser support,
you can simply test for support for the property window.matchMedia
.
window.matchMedia()
in detail
When you call window.matchMedia()
, it returns a
MediaQueryList
object, which really is just an ordinary JavaScript
object containing some useful methods and properties for us to examine the
outcome of the match. Lets look at the returned properties first.
Property | Description |
---|---|
matches | Boolean that returns true if the current state of the window matches the conditions defined in the CSS query string, or false if not. |
media | Returns the serialized media query list. In the case of
the operation: var mql = window.matchMedia("screen and (max-width: 765px)")
"screen and (max-width: 765px)" and in IE (as of IE11) browsers, the same value, but with no space between a property and its value: "screen and (max-width:765px)"
Furthermore, in IE, if a media is not specified (ie: " var mql = window.matchMedia("(max-width: 765px)") The property Due to these differences, when probing the |
The property you'll most frequently be referring to is "matches
",
which returns true when our constructed media query matches the current
state of the window. The following easily checks at run time if the user's
browser width is 800px or more:
var mql = window.matchMedia("screen and (min-width:
800px)")
if (mql.matches){ // if media query matches
alert("Window is 800px or wider")
}
else{
// do something else
}
Now, the above code only runs the desired CSS media query and compares it
to the current window state once at run time, and doesn't react to any
changes to the later thereafter. At this point the code is hardly
responsive. In order to utilize window.matchMedia()
in a
responsive manner, we need to also make use of its methods/ event handlers:
method | Description |
---|---|
addListener( functionref) | Adds a new listener function, which is executed whenever the state of the window changes and triggers a re-evaluation of the defined CSS media query. |
removeListener(functionref) | Removes a previously added listener function from listening in on changes between the current state and the defined CSS media query. |
The key method to befriend is addListener()
. By a function
to wrap the code we want to run and enter it into addListener()
,
our function will now fire whenever any changes to the current window state
leads to a match against the defined CSS media query. In other words, our
code can now react to not just a CSS media query match at run time, but
whenever the window state changes..
The following code uses addListener()
to react to a CSS
media query not just on run time, but also when any changes to the window
state occur:
function mediaqueryresponse(mql){
if (mql.matches){ // if media query matches
console.log("The condition " + mql.media + " has been met")
}
else{
console.log("Condition not met yet")
}
}
var mql = window.matchMedia("screen and (max-device-width: 480px) and
(orientation: portrait)")
mediaqueryresponse(mql) // call listener function explicitly at run time
mql.addListener(mediaqueryresponse) // attach listener function to listen in
on state changes
Here we've defined a listener function mediaqueryresponse()
.
Notice how such a function is inexplicitly passed the MediaQueryList
object from the call to window.matchMedia()
, allowing our
function to process the result. One curious line in the above code is the
call to our mediaqueryresponse()
function, in addition to
passing it into addListener()
. This may seem redundant, but
it's important to note that addListener()
only fires when the
state of the window changes, which doesn't occur when the page first loads.
The explicit call to mediaqueryresponse()
ensures that this
function is also executed when the page loads.
Now we have all the pieces in JavaScript to respond to a CSS media query.
One caveat of bringing JavaScript into the equation is often the need to
duplicate the media query twice in your page- once in your CSS @media
rule, and again in JavaScript, depending on what you're trying to do. This
could lead to maintenance issues, as it's easy to change one query but
forget to update the same for the other. But that's really a small price to
pay for the added robustness the language brings to sculpting responsive
pages.
- Introduction to CSS media queries
- width versus device-width
- The viewport meta tag- the key to preparing a page for mobile devices optimization
- CSS media query matching in JavaScript using window.matchMedia()
End of Tutorial