npm install mq-js --save

mq-js was inspired by the mq-scss Sass mixin. I wanted to use media queries in JavaScript in a similar sort of way to how I was using media queries in my Sass code.


// MQ-JS

if (mq.inside(600, 1000)) {
  // functionality for screens
  // between 600px and 1000px
}

// MQ-SCSS

@include mq(inside, 600px, 1000px) {
  // styles for screens
  // between 600px and 1000px
}

This documentation assumes that you have the ability to use ES6 JavaScript syntax in your project. mq-js will work in environments that don't support es6 JavaScript syntax however the syntax will be different to what is documented. View the full documentation for ES5 (IE friendly) examples.

If you are new to Node and npm, read this beginners guide on how to get set up. You will also need JavaScript bundling software such as Browserify, Rollup, or Webpack integrated into your build process for mq-js to work.

Once that is all set up, install mq-js using npm.

npm install mq-js --save

Now, create this simple mq.js file to set up your website breakpoints.


///////////////////
// "mq.js" file //
/////////////////

import MQ from "mq-js";

// Define your Site break points here
const bp = {
  small: 600,
  medium: 980,
  large: 1200
}

// Creates the media query functions
const mq = new MQ(bp);

// Export mq by default
export default mq;

// Gives easy access to your site breakpoints
export { mq, bp }

///////////////////
// "mq.js" file //
/////////////////

var MQ = require("mq-js");

// Define your Site break points here
var bp = {
  small: 600,
  medium: 980,
  large: 1200
}

// Creates the media query functions
var mq = new MQ(bp);

// Export mq and bp variables
module.exports.mq = mq;
module.exports.bp = bp;

Now import the mq variable into your main/component JavaScript file.


////////////////////////
// Component js file //
//////////////////////

// Import the mq variable that was created in the setup stage
import mq from "../mq";

// Alternatively import both the mq variable and the website breakpoints
// (Use one line or the other, do not use both import statements)
import { mq, bp } from "../mq";

document.querySelector('#button').onclick = function(e) {
  e.preventDefault();

  // Use your breakpoints by parsing in a string
  mq.min('medium', screen_size => {
    this.classList.toggle('-active');

    // Log the screen height, width and ratio at the time the button was clicked
    console.log(screen_size);
  })

  // Alternatively, use it in an if statement
  if (mq.max('small')) {
    // Do stuff for screens that are up to (and including) the "small" breakpoint width
  }

  // You can also use custom values
  if (mq.min(1000)) {
    // Do stuff for screens that are greater than 1000px wide
  }

  // If you imported the breakpoints, you can use tweaked versions of them
  if (mq.inside(bp.small + 50, bp.medium - 100)) {
    // Do stuff for screens that are between the "small" breakpoint + 50px
    // and the "medium" breakpoint - 100px
  }
}

////////////////////////
// Component js file //
//////////////////////

// Import the mq and bp variables that were created in the setup stage
var mq = require("../mq").mq;
var bp = require("../mq").bp; // this line is optional

document.querySelector('#button').onclick = function(e) {
  e.preventDefault();
  var self = this;

  // Use your breakpoints by parsing in a string
  mq.min('medium', function(screen_size) {
    self.classList.toggle('-active');

    // Log the screen height, width and ratio at the time the button was clicked
    console.log(screen_size);
  })

  // Alternatively, use it in an if statement
  if (mq.max('small')) {
    // Do stuff for screens that are up to (and including) the "small" breakpoint width
  }

  // You can also use custom values
  if (mq.min(1000)) {
    // Do stuff for screens that are greater than 1000px wide
  }

  // If you imported the breakpoints, you can use tweaked versions of them
  if (mq.inside(bp.small + 50, bp.medium - 100)) {
    // Do stuff for screens that are between the "small" breakpoint + 50px
    // and the "medium" breakpoint - 100px
  }
}

Note: mq.max is inclusive of the given screen size and mq.min is exclusive of the given screen size. This is to avoid any potential 1px overlap issues where both statements return true at the same time. It is also designed to align with how mq-scss works.

It is also worth noting that you can save your breakpoints into a json file and import that instead. This can make the breakpoints a bit more portable.


{
  "//" : "breakpoints.json file",
  "small": 600,
  "medium": 980,
  "large": 1200
}

///////////////////
// "mq.js" file //
/////////////////

import MQ from "mq-js";

// Retrieve your site break points
import bp from './breakpoints.json';

const mq = new MQ(bp);

// Export mq by default
export default mq;

// Easier access to your site breakpoints
export { mq, bp }

///////////////////
// "mq.js" file //
/////////////////

var MQ = require('mq-js');

// Retrieve your site break points
var bp = require('./breakpoints.json');

// Creates the media query functions
var mq = new MQ(bp);

// Exports the media query functions
module.exports.mq = mq;

// Gives easy access to your site breakpoints
module.exports.bp = bp;

If you are using mq-scss in your project and have enabled em-conversions, you will need to enable them in mq-js as well.


///////////////////
// "mq.js" file //
/////////////////

import MQ from "mq-js";

// Define your Site break points here
const bp = {
  small: 600,
  medium: 980,
  large: 1200
}

// Creates the media query functions
const mq = new MQ(bp, {

  // Enable this setting to stay in sync with mq-scss em conversions
  ems: true, //Defaults to false

  // Defaults to a base conversion value of 16px since that is the typical browser default
  // It is unlikely that you will ever need to change this setting
  emBase: 16,

})

// Export mq by default
export default mq;

// Gives easy access to your site breakpoints
export { mq, bp }

///////////////////
// "mq.js" file //
/////////////////

var MQ = require("mq-js");

// Define your Site break points here
var bp = {
  small: 600,
  medium: 980,
  large: 1200
}

// Creates the media query functions
var mq = new MQ(bp, {

  // Enable this setting to stay in sync with mq-scss em conversions
  ems: true, //Defaults to false

  // Defaults to a base conversion value of 16px since that is the typical browser default
  // It is unlikely that you will ever need to change this setting
  emBase: 16,

})

// Export mq and bp variables
module.exports.mq = mq;
module.exports.bp = bp;

In the following example, the button will only turn green if you click it when the browser window is at a maximum width of 980px wide (ie. at or below the "medium" breakpoint).

To help you figure out when the button is able to be clicked, the border of the button will turn green when it is clickable.


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

document.querySelector('.btn.-max').onclick = function(e){
  e.preventDefault();

  //Use your breakpoints by parsing in a string
  mq.max('medium', (screen_size)=>{
    this.classList.toggle('-active');

    //logs the screen height, width, and ratio at the time the button was clicked
    console.log(screen_size);
  })
})

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

document.querySelector('.btn.-max').onclick = function(e){
  e.preventDefault();
  var self = this;

  //Use your breakpoints by parsing in a string
  mq.max('medium', function(screen_size) {
    self.classList.toggle('-active');

    //logs the screen height, width, and ratio at the time the button was clicked
    console.log(screen_size);
  })
})

As you can see, you can easily access the "medium" breakpoint that you defined earlier by simply parsing a string as the breakpoint value. There is no need to import the breakpoints variable from the mq.js file to use the "medium" breakpoint.

You can also use it in an if statement sort of format as shown below. All mq-js functions can be used in this if statement format. For the sake of brevity though, I'm just showing the callback format in the rest of these examples.


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

document.querySelector('.btn.-maxIf').onclick = function(e){
  e.preventDefault();

  if (mq.max('medium')){
    this.classList.toggle('-active');
  }
})

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

document.querySelector('.btn.-maxIf').onclick = function(e){
  e.preventDefault();
  var self = this;

  if (mq.max('medium')){
    self.classList.toggle('-active');
  }
})

Notice that using the callback method gives you access to the screen size data at the time the button is clicked. The if statement format does not (or at least not without custom code).

Also notice that I'm not binding and unbinding the click function on screen resize. By placing mq inside the click function, it behaves very similarly to how media queries behave in css.

One last thing. If you prefer to explicitly state that the media query is targeting "width", mq.max can also be written as mq.maxWidth. It has identical functionality, it's just personal preference.


// This code has identical functionality...
mq.max('medium', ()=> { /* ... */ });

// ...to this code
mq.maxWidth('medium', ()=> { /* ... */ });

// This code has identical functionality...
mq.max('medium', function() { /* ... */ });

// ...to this code
mq.maxWidth('medium', function() { /* ... */ });

In the following example, the button will only turn green if you click it when the browser window is at a minimum width of 981px wide (ie. above the "medium" breakpoint).


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

document.querySelector('.btn.-min').onclick = function(e){
  e.preventDefault();

  mq.min('medium', (screen_size)=>{
    this.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

document.querySelector('.btn.-min').onclick = function(e){
  e.preventDefault();
  var self = this;

  mq.min('medium', function(screen_size) {
    self.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

You might be wondering why 981px instead of 980px. While mq.max is inclusive of the breakpoint value, mq.min is exclusive of the breakpoint value. This serves two important purposes:

  1. It prevents bugs from occurring in that 1px sweet spot where both would otherwise return true.

  2. It aligns with how mq-scss handles min and max width to prevent odd bugs where JavaScript is firing but the styles aren't there to support it (or vice versa).

Also, like with mq.max, it can be written like mq.minWidth instead if you prefer.


// This code has identical functionality...
mq.min('medium', ()=> { /* ... */ });

// ...to this code
mq.minWidth('medium', ()=> { /* ... */ });

// This code has identical functionality...
mq.min('medium', function() { /* ... */ });

// ...to this code
mq.minWidth('medium', function() { /* ... */ });

mq.inside works in much the same way as it does in mq-scss.

Instead of stating one value then calling the function, you state two values then call the function.

You can state the breakpoint values in any order but the function needs to be called last (if at all). The function will be triggered if the screen width sits between the two breakpoint values when it is called.

The smaller value always gets +1 for consistency with the mq-scss mixin and to prevent 1px overlap issues.


////////////////////////
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

document.querySelector('.btn.-inside').onclick = function(e){
  e.preventDefault();

  mq.inside('medium', 'small', (screen_size)=>{
    this.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

document.querySelector('.btn.-inside').onclick = function(e){
  e.preventDefault();
  var self = this;

  mq.inside('medium', 'small', function(screen_size) {
    self.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

It can also be written as mq.insideWidth if you prefer.


// This code has identical functionality...
mq.inside('medium', ()=> { /* ... */ });

// ...to this code
mq.insideWidth('medium', ()=> { /* ... */ });

// This code has identical functionality...
mq.inside('medium', function() { /* ... */ });

// ...to this code
mq.insideWidth('medium', function() { /* ... */ });

mq.outside does what you would expect. It is the opposite of mq.inside. It will only fire if the screen width is outside of the two breakpoint values.


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

document.querySelector('.btn.-outside').onclick = function(e){
  e.preventDefault();

  mq.outside('medium', 'small', (screen_size)=>{
    this.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

document.querySelector('.btn.-outside').onclick = function(e){
  e.preventDefault();
  var self = this;

  mq.outside('medium', 'small', function(screen_size) {
    self.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

It can also be written as mq.outsideWidth if you prefer.


// This code has identical functionality...
mq.outside('medium', ()=> { /* ... */ });

// ...to this code
mq.outsideWidth('medium', ()=> { /* ... */ });

// This code has identical functionality...
mq.outside('medium', function() { /* ... */ });

// ...to this code
mq.outsideWidth('medium', function() { /* ... */ });

One of the major features found in mq-scss is that you can easily create meaningful media query variables.


///////////////////////////////////////
// Creating MQ variables in MQ-SCSS //
/////////////////////////////////////

// Set up MQ-SCSS media query variables
$MQ-btn--active: (max, $bp-medium);
$MQ-btn--inactive: (min, $bp-medium);

.btn {
  // Using the "active" variable
  @include mq($MQ-btn--active) {
    // Active styles
  }

  // Using the "inactive" variable
  @include mq($MQ-btn--inactive) {
    // Inactive styles
  }
}

Here is how to do a similar sort of thing in mq-js:


////////////////////////
// Component js file //
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

//set up the mq-js media query variables
const MQ_btn = {
  active: ()=> mq.max('medium'),
  inactive: ()=> mq.min('medium'),
};

document.querySelector('.btn.-mqVar').onclick = function(e){
  e.preventDefault();

  // Using the "active" variable
  if (MQ_btn.active()){
    this.classList.toggle('-active');
  }

  // Using the "inactive" variable
  if (MQ_btn.inactive()){
    this.classList.toggle('-inactive');
  }

})

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

//set up the mq-js media query variables
const MQ_btn = {
  active: function() {
    return mq.max('medium');
  },
  inactive: function() {
    return mq.min('medium');
  }
};

document.querySelector('.btn.-mqVar').onclick = function(e){
  e.preventDefault();

  // Using the "active" variable
  if (MQ_btn.active()){
    this.classList.toggle('-active');
  }

  // Using the "inactive" variable
  if (MQ_btn.inactive()){
    this.classList.toggle('-inactive');
  }

})

Just because you have access to the breakpoint values, it doesn't mean that you have to use them. mq-js still works if you just parse solid numbers into it.


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

document.querySelector('.btn.-pxVal').onclick = function(e){
  e.preventDefault();

  mq.max(1000, (screen_size)=>{
    this.classList.toggle('-active');

    //log the screen size at the time the button was clicked
    console.log(screen_size);
  })
})

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

document.querySelector('.btn.-pxVal').onclick = function(e){
  e.preventDefault();

  mq.max(1000, function(screen_size) {
    this.classList.toggle('-active');

    //log the screen size at the time the button was clicked
    console.log(screen_size);
  })
})

Remember that if you use mq.min it will be like adding 1 pixel to the value that you provide.


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

document.querySelector('.btn.-pxValMin').onclick = function(e){
  e.preventDefault();

  mq.min(1000, (screen_size)=>{
    this.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

document.querySelector('.btn.-pxValMin').onclick = function(e){
  e.preventDefault();
  var self = this;

  mq.min(1000, function(screen_size) {
    self.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

What if you only want to tweak one of the normal breakpoint values so that it is just a few pixels larger than the base break point? That is when it is useful to import the breakpoint variable.

In the following example, I'm importing the breakpoints variable and using it to add 30px to the "medium" breakpoint.


//////////////////////// 
// Component js file // 
//////////////////////

// import BOTH the mq variable AND the breakpoints variable
import { mq , breakpoints } from "./mq";

document.querySelector('.btn.-bpVar').onclick = function(e){
  e.preventDefault();

  //Adding 30px to the base "medium" breakpoint
  mq.min(breakpoints.medium + 30, (screen_size)=>{
    this.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

//////////////////////// 
// Component js file // 
//////////////////////

// import BOTH the mq variable AND the breakpoints variable
var mq = require("./mq").mq;
var bp = require("./mq").bp;

document.querySelector('.btn.-bpVar').onclick = function(e){
  e.preventDefault();
  var self = this;

  //Adding 30px to the base "medium" breakpoint
  mq.min(bp.medium + 30, function(screen_size) {
    self.classList.toggle('-active');

    //log the screen width at the time the button was clicked
    console.log(screen_size);
  })
})

mq-js is just a simple function that checks the current window size when it is called. It doesn't do anything fancy when you resize the window. With a little extra code though, you can easily make it run on window resize.

The following example uses Debounce to prevent the function from firing until the window has finished resizing. This improves performance and can avoid odd bugs from occurring.

The button will activate when the screen is at the correct width and deactivate when not. Clicking the button does nothing.


//////////////////////// 
// Component js file // 
//////////////////////

//import debounce from npm for better performance
//https://www.npmjs.com/package/debounce
//(needs installing with "npm i debounce")
import debounce from 'debounce';

//import the mq variable that was created in the setup stage
import mq from "./mq";

const button = document.querySelector('.btn.-onResize');

function toggleBtn(){
  button.classList.toggle('-active', mq.inside('medium', 'small'));
};

toggleBtn();
window.onresize = debounce(toggleBtn, 200);

////////////////////////
// Component js file //
//////////////////////

//import debounce from npm for better performance
//https://www.npmjs.com/package/debounce
//(needs installing with "npm i debounce")
var debounce = require("debounce");

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

var button = document.querySelector('.btn.-onResize');

function toggleBtn(){
  button.classList.toggle('-active', mq.inside('medium', 'small'));
};

toggleBtn()
window.onresize = debounce(toggleBtn, 200);

As of version 2.0.0, mq-js supports various plugins that allow it to fully replicate everything that mq-scss can do.

These plugins can be loaded from the mq.js file to avoid the need for loading them every time you wish to use them.


///////////////////
// "mq.js" file //
/////////////////

//Loading plugins in the mq.js file for global usage

import MQ from "mq-js";

//Enables the height plugin globally
import "mq-js/plugins/height";

//Enables the orientation plugin globally
import "mq-js/plugins/orientation";

//Enables the ratio plugin globally
import "mq-js/plugins/ratio";

//Enables the reactTo plugin globally
import "mq-js/plugins/reactTo";

//Define your Site break points here
const breakpoints = {
  small: 600,
  medium: 980,
  large: 1200
}

//Creates the media query functions
const mq = new MQ(breakpoints);

//Export mq by default
export default mq;

//Gives easy access to your site breakpoints
export { mq, breakpoints }

///////////////////
// "mq.js" file //
/////////////////

var MQ = require('mq-js');

//Enables the height plugin globally
require('mq-js/plugins/height');

//Enables the orientation plugin globally
require("mq-js/plugins/orientation");

//Enables the ratio plugin globally
require("mq-js/plugins/ratio");

//Enables the reactTo plugin globally
require("mq-js/plugins/reactTo");

//Define your Site break points here
var breakpoints = {
  small: 600,
  medium: 980,
  large: 1200
}

//Creates the media query functions
var mq = new MQ(breakpoints);

//Export mq by default
module.exports.default = mq;

//Gives easy access to your site breakpoints
module.exports.bp = bp;
module.exports.mq = mq;

Alternatively, you can load all of the plugins in one statement by simply importing mq-js/ultimate;


//import all plugins at once by importing "mq-js/ultimate" instead of "mq-js"
import MQ from "mq-js/ultimate";

//import all plugins at once by importing "mq-js/ultimate" instead of "mq-js"
var MQ = require("mq-js/ultimate");

This one is pretty straight forward, it works in pretty much the same way as min, max, inside and outside except it targets height instead of width. Available functions are mq.minHeight, mq.maxHeight, mq.insideHeight and mq.outsideHeight.


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

//enables the use of minHeight, maxHeight, insideHeight and outsideHeight
//(unnecessary if it has been loaded in the mq.js file)
import "mq-js/plugins/height";

document.querySelector('.btn.-maxHeight').onclick = function(e){
  e.preventDefault();
  mq.maxHeight(600, ()=> this.classList.toggle('-active'));
});

document.querySelector('.btn.-minHeight').onclick = function(e){
  e.preventDefault();
  mq.minHeight(600, ()=> this.classList.toggle('-active'));
});

document.querySelector('.btn.-insideHeight').onclick = function(e){
  e.preventDefault();
  mq.insideHeight(800, 400, ()=> this.classList.toggle('-active'));
});

document.querySelector('.btn.-outsideHeight').onclick = function(e){
  e.preventDefault();
  mq.outsideHeight(800, 400, ()=> this.classList.toggle('-active'));
});

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

//enables the use of minHeight, maxHeight, insideHeight and outsideHeight
//(unnecessary if it has been loaded in the mq.js file)
require("mq-js/plugins/height");

document.querySelector('.btn.-maxHeight').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.maxHeight(600, function(){
    self.classList.toggle('-active');
  });
});

document.querySelector('.btn.-minHeight').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.minHeight(600, function(){
    self.classList.toggle('-active');
  });
});

document.querySelector('.btn.-insideHeight').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.insideHeight(800, 400, function(){
    self.classList.toggle('-active');
  });
});

document.querySelector('.btn.-outsideHeight').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.outsideHeight(800, 400, function(){
    self.classList.toggle('-active');
  });
});

The height plugin is the main reason why I have provided the alternate names for the width based commands. When you are combining height and width media queries in an if statement it can be easier to read mq.minWidth(800) && mq.minHeight(400) than mq.min(800) && mq.minHeight(400).

This one is even simpler. One little gotcha is that there is no "square" orientation type in css. There is only portrait and landscape types. Square screen types seem to fall under portrait in css so I've made square screen types fall under portrait in mq-js as well.


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

//enables the use of mq.orientation
//(unnecessary if it has been loaded in the mq.js file)
import "mq-js/plugins/orientation";

document.querySelector('.btn.-landscape').onclick = function(e){
  e.preventDefault();
  mq.orientation('landscape', ()=> this.classList.toggle('-active'));
});

document.querySelector('.btn.-portrait').onclick = function(e){
  e.preventDefault();
  mq.orientation('portrait', ()=> this.classList.toggle('-active'));
});

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

//enables the use of mq.orientation
require("mq-js/plugins/orientation");

document.querySelector('.btn.-landscape').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.orientation('landscape', function(){
    self.classList.toggle('-active');
  });
});

document.querySelector('.btn.-portrait').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.orientation('portrait', function(){
    self.classList.toggle('-active');
  });
});

This one is a little more complex. The ratio's for mq-js are always formatted as [width] / [height]. Ratios work off of width more so than height in CSS so mq-js does as well. So a ratio of 2 / 3 is counted as being larger than a ratio of 1 / 3 since 2 / 3 is wider than 1 / 3.

With this in mind, the ratio plugin provides you with all the typical ranges but for ratios.


//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

//Enables the use of ratio, minRatio, maxRatio, insideRatio and outsideRatio
//(unnecessary if it has been loaded in the mq.js file)
import "mq-js/plugins/ratio";

document.querySelector('.btn.-exactRatio').onclick = function(e){
  e.preventDefault();
  mq.ratio(1 / 2, ()=> this.classList.toggle('-active'));
});
document.querySelector('.btn.-minRatio').onclick = function(e){
  e.preventDefault();
  mq.minRatio(1 / 2, ()=> this.classList.toggle('-active'));
});
document.querySelector('.btn.-maxRatio').onclick = function(e){
  e.preventDefault();
  mq.maxRatio(1 / 2, ()=> this.classList.toggle('-active'));
});
document.querySelector('.btn.-insideRatio').onclick = function(e){
  e.preventDefault();
  mq.insideRatio(1 / 2, 3 / 2, ()=> this.classList.toggle('-active'));
});
document.querySelector('.btn.-outsideRatio').onclick = function(e){
  e.preventDefault();
  mq.outsideRatio(1 / 2, 3 / 2, ()=> this.classList.toggle('-active'));
});

//////////////////////// 
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

//Enables the use of ratio, minRatio, maxRatio, insideRatio and outsideRatio
//(unnecessary if it has been loaded in the mq.js file)
require("mq-js/plugins/ratio");

document.querySelector('.btn.-exactRatio').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.ratio(1 / 2, function(){
    self.classList.toggle('-active');
  });
});
document.querySelector('.btn.-minRatio').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.minRatio(1 / 2, function(){
    self.classList.toggle('-active')
  });
});
document.querySelector('.btn.-maxRatio').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.maxRatio(1 / 2, function(){
    self.classList.toggle('-active');
  });
});
document.querySelector('.btn.-insideRatio').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.insideRatio(1 / 2, 3 / 2, function(){
    self.classList.toggle('-active');
  });
});
document.querySelector('.btn.-outsideRatio').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.outsideRatio(1 / 2, 3 / 2, function(){
    self.classList.toggle('-active');
  });
});

You can also provide the ratio as a string instead.


document.querySelector('.btn.-maxRatioString').onclick = function(e){
  e.preventDefault();
  mq.maxRatio('1 / 2', ()=> this.classList.toggle('-active'));
});

document.querySelector('.btn.-maxRatioString').onclick = function(e){
  e.preventDefault();
  var self = this;
  mq.maxRatio('1 / 2', function(){
    self.classList.toggle('-active');
  });
});

This plugin is a bit different to the others. The primary purpose of this plugin is to fire off functions when a media query either enters or leaves a defined screen size range.

It takes a function that returns an mq-js screen-check result as it's first parameter and a callback function as it's second parameter. It will then call the callback function every time the screen-check result changes from true to false or false to true.


////////////////////////
// Component js file // 
//////////////////////

//import the mq variable that was created in the setup stage
import mq from "./mq";

//Enables the use of reactTo
//(unnecessary if it has been loaded in the mq.js file)
import "mq-js/plugins/reactTo";

const button = document.querySelector('.btn.-reactTo');

mq.reactTo(()=> mq.inside(800, 1000), (is_active, screen_size)=> {

  // Add the "-active" class when active, remove it when inactive
  button.classList.toggle('-active', is_active);

  // is_active = did "mq.inside(800, 1000)" return true?
  // screen_size = an object holding the screen height, width,
  //   and ratio (ratio in both string and number format) at the
  //   point when the screen crossed an mq boundary
  console.log(is_active, screen_size);
});

button.onclick = e => e.preventDefault();
  

////////////////////////
// Component js file //
//////////////////////

//import the mq variable that was created in the setup stage
var mq = require("./mq").mq;

//Enables the use of reactTo
//(unnecessary if it has been loaded in the mq.js file)
require("mq-js/plugins/reactTo");

var button = document.querySelector('.btn.-reactTo');

function is_inside(val1, val2) {
  return function(){
    return mq.inside(val1, val2);
  }
}

mq.reactTo(is_inside(800, 1000), function(is_active, screen_size) {

  // Add the "-active" class when active, remove it when inactive
  button.classList.toggle('-active', is_active);

  // is_active = did "mq.inside(800, 1000)" return true?
  // screen_size = an object holding the screen height, width,
  //   and ratio (ratio in both string and number format) at the
  //   point when the screen crossed an mq boundary
  console.log(is_active, screen_size);
});

button.onclick = function(e) {
  e.preventDefault()
};

mq-js has a lot of complicated functionality that I needed to be able to test effectively. Doing it with demos by eye wasn't cutting it.

I built a custom unit testing framework to do this.

I needed the testing framework to do the following:

  • Open 2 new windows when it starts.
  • One window needed it's media queries to be sized using em units and the other needed to be sized using px units.
  • Every test needed to be able to resize those windows to an exact pixel size.
  • The em window needed to factor font size into it's window size calculation.
  • Each test needed to occur one at a time and not get affected by any other tests.

I'm pretty happy with the testing framework that I came up with. If you would like to see it in action, open Firefox and press the button below.

To view the detailed test results, click on one of the windows that appear and press the F12 key to bring up dev tools. Click on the "console" tab to view the test results.

The tests don't work properly in Chrome because window.outerWidth - window.innerWidth does not have a stable value in Chrome.

Author:
Daniel Tonon
Licence:
MIT
Repository:
GitHub