Introducing the Media Query

Published on , in Front-end with no comments .

In the last post I gave an overview of what responsive design is and what problems it solves. In this post I’ll look at how we can implement a responsive site by looking into the viewport and CSS media queries. This post will not cover design principles such as mobile first or grid systems, but will demonstrate how media queries work and how to apply them to a page.

The HTML5 Doctype


<!DOCTYPE html>

The HTML5 doctype, unlike all previous doctypes, is short and simple. You no longer need head tags with doctype attributes and it even works in older browsers.

The Viewport Meta Tag

The viewport is basically the browser window. On a desktop computer it can be resized to show more or less of a page. The min and max width media queries that I’ll demonstrate below use the viewport dimensions, so resizing a browser will trigger these media queries. Device width and height media queries though, use the device resolution. Resizing the browser window won’t trigger these media queries.

For a more in depth (and recommended) look at viewports then take a look at this article on QuirksMode.

The viewport meta tag looks like this:


<meta name="viewport" content="">

The content property can contain a comma delimited list of values, some of which I’ll cover below.


<meta name="viewport" content="width=480">

With width=480 your viewport width will be set to 480px.

For a responsive layout its far better to base the viewport on the device size like in the following eample. Otherwise, with a setting like the one above, in higher resolution screens or in a different orientation your page will either be stretched to fit or won't fill the screen.


<meta name="viewport" content="width=device-width">

You can use initial-scale to set the zoom level with the following line:


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

By doing this the page will be displayed at full size (a 1:1 scale) on load. You can even disable zooming by the user by using one of the following lines with the last combining the properties of the first two to be sure.


<meta name="viewport" content="maximum-scale=1">
<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="maximum-scale=1, user-scalable=no">

Responsive sites will usually use the properties above like in the following two examples.


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

Media Queries

If you’re not yet familiar with media queries then you can think of them like hooks that will apply different CSS if the requirements are met. They allow you to optimise a site for all kinds of devices by checking for things like:

  • Width and height (of the viewport)
  • Width and height (of the device (resolution))
  • Orientation (landscape or portrait)
  • Pixel ratio/pixel density (DPI)

If the user’s browser supports media queries then we can use them to alter the layout, or even radically change it. View the demo below to see a working example of the code on this page. To see a fully functioning site with media queries then take a look at this site or the others listed in my previous post.

Viewport Width and Height

To change something on the page based on the viewport width or height we simply use the min-width, max-width, min-height or max-height. As I wrote above, the viewport is the browser so resizing the browser will trigger these media queries.


@media only screen and (max-width: 700px) {
    #max-width {
        display: block;
    }
}

Device Width and Height

To change something on the page based on the device width or height (resolution) we use the min-device-width, max- device-width, min-device-height or max-device-height. Resizing the browser will not trigger these media queries.


@media only screen and (max-device-width: 700px) {
    #max-width {
        display: block;
    }
}

Orientation

To base something on the orientation of the device we can use orientation: portrait or orientation: landscape.


@media only screen and (orientation: portrait) {
    #max-width {
        display: block;
    }
}

Pixel Ratio

To display or hide things based on the pixel ratio of the device we can use CSS like the following example.


@media only screen and (device-pixel-ratio: 1.5),
only screen and (-webkit-device-pixel-ratio: 1.5),
only screen and (-moz-device-pixel-ratio: 1.5),
only screen and (-o-device-pixel-ratio: 3/2) {
    #pd-1-5 {
        display: block;
    }
}

Note that Opera will only accept ratio values for all pixel ratio CSS properties whereas other browsers accept number values.

DPI Resolution Pixel Ratio
Low 320x480 1
Medium 480x800 1.5
High 720x1280 2
iPhone 4 640x960 2

Combinations

Media queries can be combined by following the same format of the pixel-ratio demo above. In this example the element will only be shown between 600px and 700px, and below 500px.


@media only screen and (min-width: 600px) and (max-width: 700px),
only screen and (max-width: 500px) {
    #min-and-max-width-multiple {
        display: block;
    }
}

A Pixel != a Pixel

Pixel ratio is an interesting one. You may have noticed while testing the viewport width or height above that you didn’t quite get the results you expected. This will likely be down to the pixel ratio.

I have a Galaxy Nexus with a resolution of 1280x720 and a screen size of 4.65″. This results in a DPI of 316 which means it has a pixel ratio of 2. If I hold it in portrait position (width = 720px) and have a media query which states a minimum width like below.


@media only screen and (min-width: 361px) {
    #min-width {
        display: block;
    }
}

You’d think that the element would be displayed on screen… except it isn’t. Even though the width in pixels of the screen in portrait mode is 720 the pixel ratio means that the 361 in the media query above gets doubled to 722 and as a result my device doesn’t meet the minimum width requirement.

Similarly, for a device with a pixel ratio of 1.5 the 361 would be multiplied by 1.5 to become 542. So the viewport would need to be a minimum of 542px for the element to be shown on screen.

This is because using width or height in a media query uses what’s known as CSS pixels (or the official term Density–Independent Pixels aka Device–Independent Pixels) whereas device width and height uses device pixels. CSS pixels are scaled for consistent sizing of the interface across different DPIs. If it didn’t then text which would be perfectly readable on a device with a pixel-ratio of 1 would be unreadable on a device with a pixel-ratio of 2. In fact, everything would be half the size. Have a look at this article for more information on CSS units.

CSS Dimensions Pixel Ratio Actual Dimensions
100x100 1 100x100
100x100 1.5 150x150
100x100 2 200x200

Where to Use Media Queries

As you’ve seen above I’ve used media queries within the CSS but you can also use them in link tags to conditionally load different CSS files.


<link rel="stylesheet" media="screen and (max-width: 700px)" href="small.css" />

You can still use the media queries demonstrated in my demo, such as pixel-ratio and orientation, in this method.

Media Queries and IE

Naturally, everyone’s favourite browser, IE (well it is, isn’t it?) doesn’t support media queries below version 9. This doesn’t actually matter because the browsers that do matter (mobile browsers), do support media queries. If, however, you still want (or need) to have functioning media queries in old versions of IE then some polyfills do just the trick. Respond.js and css3-mediaqueries.js will enable your responsive site to function as you intended in browsers that don’t natively allow it.

Respond.js is deliberately narrow in its scope, supporting only IE6–8 and only enabling min-width and max-width media queries. If you need more media queries than just those two, and support in more browsers such as old versions of Firefox, Chrome or Safari then css3-mediaqueries.js is the next best option.

Applying Media Queries to a Page

In this example I have a basic page structure consisting of a header, content area, left and right sidebars and a footer containing 4 columns.

At full size, the container is 1000px wide with the header and footer always at full width (978px). The sidebars come in at 24% wide and the main content area is 48%. The columns in the footer are 23.5% wide.


#container {
    background-color: white;
    border: 1px solid #CCC;
    margin: 20px auto;
    padding: 10px;
    max-width: 978px;
    width: 90%;
}
#left, #main, #right {
    float: left;
    width: 24%;
    height: 200px;
    margin: 2% 2% 2% 0;
}
#main {
    width: 48%;
}
.col {
    background-color: #F8F8F8;
    width: 23.5%;
    margin-right: 2%;
    margin-bottom: 2%;
    float: left;
}

Let’s say that our right column contains some advertisements which we’d like to hide to visitors on smaller screens. At 800px we do this with the following media query where the main content area expands to cover the space left behind by the sidebar.


@media screen and (max-width: 800px) {
    #right {
        display: none;
    }
    #main {
        width: 74%;
        margin-right: 0;
    }
}

At 600px things are getting a little bit tight so let’s switch things around a bit and go for a single column layout but with a two column footer.


@media screen and (max-width: 600px) {
    #left, #main {
        float: none;
        width: 100%;
    }
    .col {
        width: 47%;
    }
    #second {
        margin-right: 0;
    }
}

And finally at 480px we switch fully into a single column layout.


@media screen and (max-width: 480px) {
    .col {
        float: none;
        width: 100%;
        padding: 1px 0;
    }
}

One thing I touched on in my last post was breakpoints. Breakpoints are the dimensions at which we alter the page layout or design. Sometimes I come across people asking about which resolutions they should add media queries. Well, you don’t have to stick to resolutions. It’s actually better, and more than likely necessary, that you don’t. There are no rules regarding breakpoints. They can be added wherever and as often as you like. If you look at responsive sites you’ll see that the media queries don’t match against resolutions, but they match the design. The breakpoints have been added to alter something at the point the design breaks. As I said in my previous post:

“There is no rule as to how many breakpoints a page should have, but one should be added wherever the layout breaks. The aim is to make sure the design and content flows nicely regardless of the width of the viewport.”

That’s all folks. Hopefully you’ll now have a better understanding of media queries and how to use them. Feel free to save a copy of the demo files and play around with them by altering and adding your own media queries. Responsive sites can seem very complex and daunting at first but you’ll soon realise it’s not too difficult and you’ll be creating your own responsive sites in no time.

Leave a Comment