&

ūüí¶

Media queries

Empty your mind. Be formless, shapeless, like water. You put water into a cup, it becomes the cup. You put water into a bottle, it becomes the bottle. You put it into a teapot, it becomes the teapot. Now water can flow or it can crash. Be water, my friend.

Bruce Lee

Content is like water. Content’s going to take many forms, flow into many different containers, many of which we haven’t even imagined yet. Build from content out, not container in.

Josh Clark

What is responsive design?

Let‚Äôs first take a¬†minute to¬†talk about responsive design. This term was coined in¬†2010 or so by Ethan Marcotte‚ÄĒwrapping a¬†name around a¬†progressive enhancement and¬†mobile-first web design approach/philosophy that had been growing in¬†the mid-2000s (sometimes called liquid, flexible, fluid, or elastic design).

Instead of¬†building, designing, and serving a¬†desktop site and a¬†separate, minimal mobile version (if¬†you even did at¬†all)‚ÄĒyou could instead adapt one site.

There was a¬†confluence of¬†events that allowed this: modern, self-updating browsers, and then the explosion of¬†the mobile web‚ÄĒprecipitated, in¬†no small part, by the iPhone in¬†2007. It¬†ran a¬†desktop-class browser (in terms of¬†functionality), which hadn‚Äôt been available in¬†a¬†small screen before. And with its crazy success‚ÄĒand the subsequent proliferation of¬†its paradigm in¬†Android‚ÄĒthe¬†web, and then world, scrambled to¬†respond.

A typical/example responsive layout, adjusting the content to reflow based on the device width.

A typical/example responsive layout, adjusting the content to reflow based on the device width.

The viewport

There wasn’t much of a mobile web, prior to the iPhone. Some sites had barebones WAP mobile versions, designed for the tiny screens and limited hardware of the era.

When the iPhone came on the scene, most desktop websites still didn‚Äôt have narrow/smaller (let alone flexible) layouts‚ÄĒso¬†the phone would instead scale or¬†zoom out a¬†desktop site design down to¬†fit.

Websites at the time were often designed to¬†a¬†standard width (usually 960px), which the phone shrank down to¬†its 320px screen‚ÄĒand then the user could zoom in¬†or¬†out, scrolling around to view the whole¬†page.

It¬†somewhat worked‚ÄĒand all the content was there, unlike most mobile sites‚ÄĒbut it¬†was less than¬†ideal.

This is how the Times looked on your RAZR.
This is how the Times looked on your RAZR.
The iPhone’s introduction is worth a watch. Safari!
The iPhone’s introduction is worth a watch. Safari!
Their full desktop site scaled down, on an iPhone. Simpler times, those.
Their full desktop site scaled down, on an iPhone. Simpler times, those.

You’ll see this in the <head> of most websites, now:

<meta name="viewport" content="width=device-width, initial-scale=1">

This meta element tells the browser not to¬†do this scaling. It¬†says, ‚ÄúI¬†have a¬†responsive design! Render me at¬†my actual size. My content can reflow.‚ÄĚ

The Times wasn’t fully responsive until 2018! They still maintained a separate mobile site and apps.
The Times wasn’t fully responsive until 2018! They still maintained a separate mobile site and apps.

The width=device-width tells the browser to use whatever the screen’s actual pixel dimension is, and the initial-scale=1 sets the starting zoom for the page to 100%. This is how the browser knows how to make the page respond, and how our CSS rules know what width to use.

We call the portion of the page visible at one time the viewport.

Media queries

Responsive design could only really flourish when CSS added the @media at-rule around the same time.

These are colloquially called media queries, and they allow¬†us to¬†check if screen is a¬†certain width or resolution (or¬†other features, which we‚Äôll get to)‚ÄĒand then apply selective CSS only in¬†that scenario/situation. These let site layouts respond intentionally to¬†different devices, for¬†the first¬†time.

Practically, these are blocks of¬†CSS‚ÄĒa little bit like selectors that contain other selectors‚ÄĒbut which only apply conditionally when the test/criteria is met.

These blocks are like any other CSS‚ÄĒif there are multiple conditions that are met, or there is a¬†tie between properties‚ÄĒthe rules cascade down and the lowest/last one takes precedent.

/* Our CSS has all been out here! */

@media some-criteria-or-rule {
  /* CSS that only applies if a test passes. */
}

Width-based breakpoints

There are many¬†media queries we can use, but we‚Äôll start with width‚ÄĒwhich is by far the most commonly-used and really the core of¬†responsive design. Usually when folks are talking about a¬†page or site being responsive, they¬†mean with regards to its ¬†width.

This is from more than ten years ago. It’s only gotten worse.
This is from more than ten years ago. It’s only gotten worse.

Width tends to vary the most across devices‚ÄĒfrom the¬†375px‚Äď428px of¬†your phones, through to the ~1440px‚Äď1680px of¬†your laptops, and then on up to¬†the¬†~2560px‚Äď3440px you might see with large, desktop displays.

Since this width is usually our primary design constraint (height being handled through scrolling), we need width-based media queries to adjust our layouts across this wide range, lest our designs fall.

This is done in¬†steps, at different widths, that we call breakpoints‚Ā†‚ÄĒthe window/device/viewport sizes where the content starts to¬†break, if it¬†is not adjusted.

This might be because lines of¬†text get too short or too long, becoming hard to¬†read. It¬†might be to¬†prevent a¬†grid of¬†images from becoming too small on a¬†phone‚ÄĒwhile you can have many columns on desktop, often you can only have one or two on mobile. You can add as many breakpoints as you need to¬†make your page/design work across devices. Don‚Äôt think of these as written for specific devices; write for your design and your¬†content!

There are very, very few layouts that won’t need some amount of horizontal responsiveness/breakpoints!

If you think responsive’s simple, I feel bad for you son. We got 99 viewports, but the iPhone’s just one.

Josh Brewer

In this example, we would refer to 480px as our breakpoint:

Drag the code/example divide to the left to see it respond to the media query!
You can double-click to reset it.

This width rule/test/criteria uses the same syntax as length properties, meaning you can use min-width, width, and max-width:

Again, drag the divide to see rules apply. Exact matches (like the width: 480px; here) are rarely useful!

Height-based, too

You can also use height in¬†the same way‚ÄĒthough again, with the usual vertical scrolling paradigm, height-based adjustments aren‚Äôt as necessary or anywhere nearly as¬†common.

This example is the same breakpoint of 480px, but now using height:

These code examples are responsive, themselves‚ÄĒstacking like this when they are¬†narrow.

In a broader code and programming context, it can be helpful to think of media queries as conditional if statements.

We’ll talk about this in detail later with JavaScript, where conditionals are ubiquitous and powerful. You may have also heard of If This Then That, which takes its name from this kind of logic.

Orientation

You can also be less specific about your width/height and instead use orientation‚ÄĒlike when you rotate your phone. The queries use the wonderfully tenacious names/values of¬†portrait or landscape:

Everything was a painting before it was a photograph or a web page.

And/or combinations

And speaking of¬†conditional statements‚ÄĒyou can also merge multiple media queries into one test/check, using and. This is often used for a¬†range (to apply something between two breakpoints) or to¬†combine width and¬†height checks, together:

The demo here is taller than 360px, for the second one.

You can also use comma-separated queries (similar to¬†selector lists) to¬†apply or¬†logic‚ÄĒsetting the same styles for different scenarios:

Note that you could do this with and, as in the example above, by just swapping the colors. Code logic!

There is also a¬†not logic operator‚ÄĒwhich will reverse the¬†meaning of¬†the media query. But this syntax gets confusing fast‚ÄĒespecially with things like min¬†/¬†max rules making for double-negatives. So it¬†is easier to¬†avoid!

Why say not portrait when you can just say… landscape?

Mobile-first design

So this can all get very complicated, very quickly‚ÄĒespecially with complex designs, overlapping rules, and¬†the wide ranges of¬†devices to¬†consider.

One of the easiest methodologies to keep things understandable is practicing mobile-first design (and development). This has become kind of buzzwordy in the past decade or so, but it is a good philosophy to adhere to, nonetheless.

Your design constraints will be tighter and more challenging, by tackling your smallest layout first‚ÄĒbut it¬†is almost always easier to¬†scale things up than scale them down. A¬†mobile design can always work as a¬†passable desktop one; the reverse is rarely true.

(Another way to think of it: if it doesn’t work on mobile, it doesn’t work.)

Note we added a main container. The width here are kind of¬†tricky‚ÄĒbut this will be¬†much easier with grid, we promise!

This follows the general CSS pattern/paradigm of¬†the cascade‚ÄĒand is much, much, much easier than adjusting desktop front-end after the fact. (Trust¬†us.) Always think mobile-first!

Briefly, CSS variables

Custom properties (folks almost always say CSS variables) aren‚Äôt strictly a¬†part of¬†responsive design or media queries, per¬†se‚ÄĒbut they come up very often in¬†modern, mobile-first practice and we‚Äôll introduce them briefly, here.

These bring another programming concept of¬†variables into CSS. These are shorthand entities for values we want to¬†reuse throughout a¬†document‚Ā†‚ÄĒor, in¬†a¬†responsive context, want to¬†modify at certain breakpoints.

Changing the value of¬†a variable changes it¬†everywhere it¬†is referenced‚ÄĒno copy/pasting or find/replacing. (You¬†could think of¬†a color swatch, if you are in¬†an Adobe¬†mindset.) Again, these are just for you‚ÄĒit is all the same to¬†the computer. More¬†ergonomics!

In your CSS, you declare (set) these with a -- prefix in front of a subjective name you make up. And you reference (use) them by wrapping that variable name in var():

:root {
	--brand-color: #e42a1d; /* Declare it. */
}

.brand-color {
	color: var(--brand-color); /* Reference it. */
}

You can use these as values for any CSS property‚ÄĒcolors, spacing, etc.‚ÄĒanything you use multiple times and want to¬†be consistent, or want to¬†easily change:

Changing the spacing here would be easy, even though we use it a bunch.

You‚Äôll often declare a¬†set of¬†variables for mobile‚ÄĒtype sizes, spacing, and so on‚ÄĒand then adjust them, once, for¬†desktop. No need to¬†write all the properties out again, with all their own redundant media-queries! Variables are¬†great. It used to be so much harder.

They‚Äôll help you avoid unwanted cascade (applying the same property), especially across breakpoints. But they also help to¬†facilitate design system thinking‚ÄĒfocusing your design on the relative relationships of¬†things.

Other media features

By far, the most common media queries will be width/height/orientation‚ÄĒfor adjusting your¬†layouts across devices. But @media has some more¬†tricks up its sleeve in¬†testing for other browser features. We‚Äôll¬†look at some of¬†the handy/common ones.

screen vs. print

In all of¬†our above examples, there is an¬†implied media¬†type of¬†screen‚ÄĒsince that is usually what we are concerned with, on the web. But there is also one for print! You can use these to¬†segment styles to¬†one medium or the other:

You can see the print style in¬†action by clicking the arrow in¬†the upper corner, then ‚Ćė P to¬†print. It¬†is still A¬†Thing, though often forgotten about in¬†modern web design/projects.

hover

Another common one is hover, used to¬†detect whether a¬†browser has¬†an input device that supports hovering‚ÄĒwhich really just means a¬†mouse, on laptop/desktop computers.

Mobile touch-based systems don’t have this behavior (and sometimes react oddly to :hover CSS), so you should adjust your interfaces to work in the absence of this state:

If you view this on your phone, the aside should be visible without interaction. On your computer, you’ll have to mouse over the div. Note how this is written with a mobile-first style, only adding the hover state later/lower for folks who have it!

Hover states are a¬†good feature for progressive-enhancement, as we did here‚ÄĒto add them in¬†after you¬†have a¬†working mobile design! Since maybe a¬†third to¬†a¬†half of¬†your audience (depending on your project) won‚Äôt see them, don‚Äôt rely on them being seen.

prefers-color-scheme

You see this one more and more these days‚ÄĒswitching up a¬†site‚Äôs styles based on whether the user is in¬†light or dark mode, popularized by the ol‚Äô iPhone again:

You’ll see this differently depending on whether your system is in light or dark mode.

Sometimes this feels appropriate‚ÄĒespecially in¬†products/applications, like maybe a¬†messaging service. But¬†sometimes the color scheme of¬†a¬†site is its brand, and¬†probably shouldn‚Äôt change based on this query. It‚Äôs¬†up to¬†you! Continuing our ongoing discussion of¬†who¬†has the¬†control.

prefers-reduced-motion, prefers-contrast

These last two are primarily concerned with accessiblity‚ÄĒfor folks who run their device/browser with animations turned off, or in¬†a¬†high-contrast mode to¬†help with their¬†vision:

button {
  animation: some-slick-animation;
}

@media (prefers-reduced-motion: reduce) {
  button { animation: none; }
}
:root {
   --background: lightgray;
   --foreground: slategray;
}

p {
	background-color: var(--background);
	color: var(--foreground);
}

@media (prefers-contrast: more) {
	:root {
		--background: white;
		--foreground: black;
	}
}
The corresponding settings in iOS.
The corresponding settings in iOS.

The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect.

Tim Berners-Lee