I\'ve been searching for a lightweight, flexible, cross-browser solution for accessing CSS Media Queries in JavaScript, without the CSS breakpoints being repeated in the Jav
try this
const mq = window.matchMedia( "(min-width: 500px)" );
The matches property returns true or false depending on the query result, e.g.
if (mq.matches) {
// window width is at least 500px
} else {
// window width is less than 500px
}
You can also add an event listener which fires when a change is detected:
// media query event handler
if (matchMedia) {
const mq = window.matchMedia("(min-width: 500px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
// media query change
function WidthChange(mq) {
if (mq.matches) {
// window width is at least 500px
} else {
// window width is less than 500px
}
}
I found an hackish but easy solution :
@media (min-width: 800px) {
.myClass{
transition-property: customNS-myProp;
}
this css property is just a markup to be able to know in JS if the breaking point was reached. According to the specs, transition-property can contain anything and is supported by IE (see https://developer.mozilla.org/en-US/docs/Web/CSS/transition-property and https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident).
Then just check in js if transition-property has the value. For instance with JQuery in TS :
const elements: JQuery= $( ".myClass" );
$.each( elements, function (index, element) {
const $element = $( element );
const transition = $element.css( "transition-property" );
if (transition == "custNS-myProp") {
// handling ...
}
});
Of course there is a word of warning in the wiki that the domain of css property identifiers is evolving but I guess if you prefix the value (for instance here with customNS), you can avoid clashes for good.
In the future, when IE supports them, use custom properties instead of transition-property https://developer.mozilla.org/en-US/docs/Web/CSS/--*.
I managed to get the breakpoint values by creating width rules for invisible elements.
HTML:
<div class="secret-media-breakpoints">
<span class="xs"></span>
<span class="tiny"></span>
<span class="sm"></span>
<span class="md"></span>
<span class="lg"></span>
<span class="xl"></span>
</div>
CSS:
$grid-breakpoints: (
xs: 0,
tiny: 366px,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px
);
.secret-media-breakpoints {
display: none;
@each $break, $value in $grid-breakpoints {
.#{$break} {
width: $value;
}
}
}
JavaScript:
app.breakpoints = {};
$('.secret-media-breakpoints').children().each((index, item) => {
app.breakpoints[item.className] = $(item).css('width');
});
See this post from expert David Walsh Device State Detection with CSS Media Queries and JavaScript:
CSS
.state-indicator {
position: absolute;
top: -999em;
left: -999em;
}
.state-indicator:before { content: 'desktop'; }
/* small desktop */
@media all and (max-width: 1200px) {
.state-indicator:before { content: 'small-desktop'; }
}
/* tablet */
@media all and (max-width: 1024px) {
.state-indicator:before { content: 'tablet'; }
}
/* mobile phone */
@media all and (max-width: 768px) {
.state-indicator:before { content: 'mobile'; }
}
JS
var state = window.getComputedStyle(
document.querySelector('.state-indicator'), ':before'
).getPropertyValue('content')
Also, this is a clever solution from the javascript guru Nicholas C. Zakas:
// Test a media query.
// Example: if (isMedia("screen and (max-width:800px)"){}
// Copyright 2011 Nicholas C. Zakas. All rights reserved.
// Licensed under BSD License.
var isMedia = (function () {
var div;
return function (query) {
//if the <div> doesn't exist, create it and make sure it's hidden
if (!div) {
div = document.createElement("div");
div.id = "ncz1";
div.style.cssText = "position:absolute;top:-1000px";
document.body.insertBefore(div, document.body.firstChild);
}
div.innerHTML = "_<style media=\"" + query + "\"> #ncz1 { width: 1px; }</style>";
div.removeChild(div.firstChild);
return div.offsetWidth == 1;
};
})();