A computer rendering of domino tiles formed into a diminishing spiral

It’s common to use matchMedia in JavaScript to create behaviors at breakpoints for responsive sites. But the fact that matchMedia takes its own breakpoint values leads to inconsistencies and confusion between JavaScript actions and CSS media query events: changing the value for a CSS breakpoint inevitably means hunting down and changing the equivalent value in your scripts to keep them in sync. Ideally, responsive actions in JavaScript should be initiated by changes in CSS. We can achieve that, using a trick I picked up from Lukas Rydygel:

First, we need a method of communicating between CSS and JavaScript. In theory, a script could pick up a style change on any element, but it makes sense to make this communication as clear and explicit as possible.

Message In A Bottle

The pseudo-elements :before and :after have the advantage of take any content as a value. Every block-level element has access to both… even the <body>. So we can use either element to contain a message that can be read by a script:

@media all and (max-width: 800px) {
	body:before { content: 'tablet'; display: none; }
}

This places a “message” on the <body> when the viewport is 800 pixels wide or less. Because it is set to display: none, only JavaScript will be able to read it, and the added text won’t disrupt .

Next, we read this message with a script:'

function checkForViewportChange () {
	var state = window.getComputedStyle(document.body,':before').content;
	this.lastState = this.lastState || "";
	if (state != this.lastState) {
		if (state == "tablet") {
			// do something when viewport switches to tablet state
		} else {
			// do something when viewport moves out of tablet mode
		}
	this.lastState = state;
}}

The ideal method of calling this function would use a mutator, but those are very new to JavaScript, and only supported by very recent browsers. Instead, polling with setInterval is used:

window.setInterval (checkForViewportChange, 150);

Changing the breakpoint of the CSS media query will alter when the JavaScript behavior fires, making the two interdependent. This technique can be extremely useful when prototyping responsive sites, as breakpoints often change frequently during development; once the work is complete, more efficient matchMedia actions could be substituted for the code.

Rendering by Matt Cavanagh, licensed under Creative Commons

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.