Responsive Web Design with the CSS @media query

I’ve recently started regularly checking my Google Analytics stats for Chriselison.uk and what I found surprised, and if I’m being honest, scared me - 43% of my visitors are accessing the site on a tablet or mobile phone, in other words, almost half of my site’s visitors are not accessing the site from a desktop computer at all!

Why was this scary to me? Well, I was guilty of never really taking into account mobile users when designing my websites, for a long time I always assumed anyone serious about looking up a website would do so in a proper desktop browser; in my mind mobile internet was nothing more than a gimmick that would never catch on, and so I designed only with desktop browsers in mind. I mean, who wants to browse Reddit on their phone? Pah!

Well, it turns out lots of people do. How wrong I was!

The m.dot website

With the advent of WAP and the increasing popularity of mobile phones in the early 2000s, companies began to offer stripped-down, mobile-friendly versions of their sites, often with the hostname m.example.com, hence the term ‘m.dot’. M.dot websites were designed specifically to load as quickly as possible over a WAP or 2G connection, but often lacked a lot of the functionality or features of their desktop equivalents.

An m.dot web page

In theory, the m.dot website was a seamless solution for a site’s mobile users, although in practice it meant having to develop and maintain an entirely new website often with its own separate backend code. There had to be a better way…

Enter the humble @media query!

@media screen and (max-width: 1200px) {

}

This seemingly innocuous line of CSS was introduced with CSS3 and has revolutionised the way websites are designed and developed today. With it we can style individual elements or the entire page depending on the size of the viewport. Let’s try a practical example:

<!-- responsive-test.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Test 1</title>
    <link rel="stylesheet" href="responsive-test.css">
  </head>
  <body>
    <div class="container">
      <p></p>
    </div>
  </body>
</html>

And the CSS:

/* responsive-test.css */
body {
  margin: 0;
  padding: 0;
}

.container {
  align-items: center;
  background-color: dodgerblue;
  display: flex;
  height: 100vh;
  width: 100%;
}

.container > p {
  color: #fff;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 48px;
  font-weight: 700;
  margin: auto;
}

.container > p:after {
  content: "Desktop!";
}

Which results in a page looking like this:

A non-responsive web page

Resizing the browser window does nothing, the ‘Desktop!’ message remains in the center of the screen. Now, let’s add a @media query to the end of the stylesheet:

...
@media screen and (max-width: 1200px) {
  
}

Now we can add some CSS rules to the media query:

...
@media screen and (max-width: 1200px) {
  .container { background-color: forestgreen; }
  .container > p:after { content: "Tablet!"; }
}

Save the file and refresh your browser. Now try resizing the width of the browser window, notice what happens!

A responsive desktop/tablet web page

Now let’s add another @media query directly after the previous!

...
@media screen and (max-width: 500px) {
  .container { background-color: crimson; }
  .container > p:after { content: "Phone!"; }
}

Save and refresh the page, try resizing your browser all the way - see what happens!

A responsive desktop/tablet/phone web page

So you can probably now see how powerful @media queries can be, we can apply any CSS rules we like to any element we like based purely on the width of the viewport! This means font sizes, container widths, background images - all can be changed with a media query!

Another example - responsive typography

Let’s try another more typographic example using media queries and CSS columns. Here’s the HTML, I’ve truncated the placeholder text:

<!-- responsive-test2.html -->
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Test 2</title>
    <link rel="stylesheet" media="screen" href="responsive-test2.css">
    <link href="https://fonts.googleapis.com/css?family=Lora:400,700&display=swap" rel="stylesheet">
  </head>
  <body>
    <div class="container">
      <h1>Offendit duis ab commodo domesticarum</h1>
      <p>
        Cernantur hic aliquip...
      </p>
      
      <h2>Concillio et laboris</h2>
      <p>
        Hic culpa an amet...
      </p>
    </div>
  </body>
</html>

And the CSS:

/* responsive-test2.css */
body {
  color: #333;
  font-family: Lora, Georgia, serif;
  font-size: 100%;
  line-height: 1.6;
  margin: 0;
  padding: 0;
}

h1 { margin: 2.6rem 0; text-align: center; }
h2 { margin-top: 2.6rem; }

.container {
  margin: auto;
  max-width: 1200px;
  padding: 3%;
}

.container > p {
  columns: 3 auto;
}

The resulting page looks something like this:

A 3-column page

The three columns layout looks great on a full-width desktop browser window, but try resizing the browser window, notice how the text columns squish together and are unreadable. It’s time to add a breakpoint to our CSS!

...
@media screen and (max-width: 960px) {
  .container > p { columns: 2 auto; }
}

Now when we resize the browser window the 3-columns turn into 2!

A 2-column page

Let’s add one final breakpoint for mobile users, we want just a single column of text this time, we’ll also left-align the <h1> element and make the text slightly larger for mobile users:

...
@media screen and (max-width: 640px) {
  body { font-size: 110%; }
  h1 { text-align: left; }
  .container > p { columns: 1 auto; }
}

Which leaves us with a page looking something like this:

A 1-column page

Have a play around with changing the font size using media queries, try to keep the text as legible and readable as possible, and if in doubt - make the text bigger! Keep your mobile users in mind and try to test on a variety of different devices.

Detecting portrait orientation with media queries

Did you know you can detect if a mobile user is using the phone/tablet in portrait orientation using just CSS @media queries? That’s right - no JavaScript required:

@media (orientation: portrait) {

}

This is useful for adjusting the height of a hero image for example. In fact, I use this very technique on this website to make article hero images take up less vertical space in portrait mode.

And finally a shoutout

I’d like to shout-out Ethan Marcotte (@beep), the pioneer of responsive web design, his article ‘Responsive Web Design’ kick-started the responsive design revolution and we have him to thank for the web being a much nicer place than it was 15 or so years ago.

Well, that’s all for now, I look forward to publishing more articles on web development and CSS soon, in the meantime be sure to follow me @ChrisElison on Twitter and Instagram!

More reading