A good[ish] website
Web development blog, loads of UI and JavaScript topics
Get media queries to JavaScript from a Sass file.
Here’s a little experiment of mine. Remember the technique, from few years back, where you would stick the name of a breakpoint into a :before
or :after
pseudo element in body tag, like this:
body {
@include bp(m) {
&:after {
content: 'm';
}
}
@include bp(l) {
&:after {
content: 'l';
}
}
@include bp(xl) {
&:after {
content: 'xl';
}
}
&:after {
content: 's';
display: none;
}
}
And then read it with JavaScript using getComputedStyle
:
var size = window
.getComputedStyle(document.body, ':after')
.getPropertyValue('content')
// Size equals to your current breakpoint now
I "improved" it a little, and made a Sass mixin to encapsulate it better. The mixin uses Sass maps, with the map value being a Sass list. More on the JavaScript bit later in the article.
This mixin sticks the breakpoints name into :before
and the breakpoints size into :after
. I have no idea if the size is needed for anything, I haven't needed it ever, but there might be a use case for it, I'll leave that up to you.
This is actually a set of mixins, it needs a breakpoint mixin as it companion. Read the comments in the code for more details:
// Media queries
$breakpoints: (
's': (
min-width,
48em
),
'm': (
min-width,
50em
),
'l': (
min-width,
64em
),
'xl': (
min-width,
90em
),
'xxl': (
min-width,
105em
)
) !default;
// Make the breakpoints
@mixin bp($breakpoint) {
$query: map-get($breakpoints, $breakpoint);
@if $query != null {
@media (#{nth($query, 1)}: #{nth($query, 2)}) {
@content;
}
} @else {
@warn "Unfortunately, no value could be retrieved from #{$breakpoint}. "
+ "Please make sure it is defined in `$breakpoints` map.";
}
}
// ----
// Here's the sauce, this jugs the BPs name (key) into an `:after` and the
// value to `:before` and `:after` pseudo elements, we can read that with
// JavaScript.
// ----
@mixin bp2js($default) {
// One of the BPs has to be the default, meaning that it's on when
// there's no BP affecting. In the min breakpoint mobile first approach,
// the default would be the smallest BP.
&:before {
$foo: map-get($breakpoints, $default);
display: none;
}
&:after {
content: '#{$default}';
display: none;
}
@each $point, $dim in $breakpoints {
@if $default != $point {
@include bp(#{$point}) {
&:after {
content: '#{$point}';
}
&:before {
content: '#{nth($dim, 2)}';
}
}
}
}
@content;
}
Demo:
Play with this gist on SassMeister.
Here's the script wrapped into an AMD module:
// mq2js.js
'use strict'
define(function () {
var getValues, value
getValues = function (el) {
value = window
.getComputedStyle(document.body, ':' + el)
.getPropertyValue('content')
return value.replace(/(\'|\")/g, '')
}
return {
name: getValues('after'),
size: getValues('before')
}
})
It returns an object called bp
with with two keys:
name
— the breakpoint namesize
— the breakpoint widthHere's an example that prints them out to the console:
define(function(require) {
// Require the module
require('./mq2js')
// Define environment. Ideally you'd check this programatically somehow
var isDev = true;
// Make a little helper function
var bpShower = function() {
console.log('BP name: ' + bp.point + 'n BP width: ' + bp.width);
}
// If on dev, run it
if (isDev === true) {
bpShower();
// Run also on resize
window.addEventListener('resize', bpShower);
}
}
Another use case for this is to load assets conditionally depending on the screen size:
define(function(require) {
// Require the module
require('./media-queries')
// Check the that we're on the large breakpoint
if (bp.point === 'xxl') {
// Load an image gallery, for example
$("#result").load("ajax/images-template.html", function() {
// This is a callback for the load,
// init lazyload here or something else...
});
}
}
This is very light and library-free method of doing this, albeit not very advanced nor sophisticated. There's libraries like enquire.js that can do tons of amazing stuff for you! Enquire.js is also dependency free, get to know it here, it's quite alright.
Comments would go here, but the commenting system isn’t ready yet, sorry. Tweet me @hiljaa if you want to make a correction etc.