If you’ve never given responsive design a try because it seems too hard, you’re not alone. I’ll admit that it took me a long time to work up the nerve to try it. Everything just seemed so complicated.
But it doesn’t have to be. I’m going to show you how to build a responsive site from scratch, the easy way. No math, and no formula.
If you keep reading, you’ll download code for a demo website that you will edit on your own computer so you can see exactly how everything works. This tutorial is based on a presentation I gave at MobileUXCamp DC in September 2012.
Is Responsive Design Really This Easy?
Remember when you learned HTML? You didn’t try to learn all of it in an hour. You started with a few tags like <p>, <b>, and <center> (depending on how long ago you learned). You learned how to add links and images. And it was pretty cool because that was all you needed to make a web page.
If you’ve tried to learn responsive design, you may have been overwhelmed by all the words coming at you: fluid grids, frameworks, retina images, targets, contexts, breakpoints, load times, conditional loading, viewports, polyfills, and seriously yes that makes even my head hurt.
So forget all of that for now. Today you’re just going to learn how to make a responsive website.
A Few Disclaimers Before We Get Started
Of course there’s a lot more to responsive design than you’ll learn in one tutorial. See the resources section at the end of this post.
And before we start, you need to know that parts of the CSS in this exercise will not work on older browsers (there are fixes for this, which you should make sure to learn later). If you use Firefox, Chrome, or Safari, you almost certainly have a recent enough version that you’re okay. If you insist on using IE, it has to be IE9.
This exercise is meant to be done on your computer as you change the width of your browser window, so the explanations are written in that context. By changing the size of your browser window, you’re simulating how the site would appear on devices of various widths. In the real world, it’s more complicated than that, but all you’re doing today is learning the basics of how CSS works on a responsive site, so your browser will suffice.
The HTML and CSS for this demo is deliberately very simple, so it may not be exactly what you would choose to code a real site. Also, the demo site uses Lorem Ipsum text. Don’t use Lorem Ipsum when designing a real site.
I’m assuming you already know the basics of what responsive design is and how it looks like in a browser. If not, go to The Boston Globe, resize your browser window a bunch of times, and pay attention to what happens.
How to Do the Tutorial
Download the zip file below and unzip. You’ll find demo.html, style.css, and a few image files.
Open the HTML and CSS files in your text editor, and open the HTML file in your browser.
In each section of the tutorial, copy and paste the piece of CSS into your style.css file, and save. Refresh and resize your browser to see what happens. Play around with the code a bit to make sure you understand it before you move on to the next section of the tutorial.
- Download the files (zip)
Are you ready? Let’s do this thing!
Fonts
You’ll notice that the HTML for the demo page is very basic, with a few divs thrown in where we’ll need them later. This tutorial is not about design, so other than the responsive layout, we’re only going to do a little formatting where it’s necessary for things to make sense.
To start, we’ll reset the size of all our fonts to 100%, and then we’ll proportionally size our fonts using ems instead of pixels. The base font size for most browsers is 16 pixels, so setting the size of p to 1em means that our paragraph text will display as 16 pixels. Setting the h1 t
o 2em means our headings will display as twice the base size of 16 pixels, which would be 32 pixels.
Using ems for fonts is a good practice, whether or not your design is responsive.
h1, p, li { font-size: 100%; } h1 { font-size: 2em; font-weight: 700; } p, li { font-size: 1em; }
Flexible Images
One component of responsive design is flexible images. We want the images on our page to be able to expand and contract as needed so they fit in spaces where we want them to fit.
Please note that it’s important to not manually set a height or width for images, otherwise our flexible images won’t be flexible. All of our image files need to start out sized at the largest dimension we want them to be on the page. They will display at their actual size until our CSS tells them otherwise.
The Responsive Design logo at the top of demo.html is 550 pixels wide. If you make your browser window narrower than 550 pixels, the right edge of the image is no longer visible. We’re going to fix that.
(And yes of course our “logo” could be done with CSS instead of using an image, but then I wouldn’t have a too-wide image at the top of the page to point to, would I?)
By setting the max-width of all images to 100%, we’re telling the browser that the maximum size it should display images at is 100% of the width of their containing element. In other words, if an image is supposed to be in something smaller than the image, the image will get smaller so that it fits in the container.
Add this CSS to your style.css file, and you’ll see that when you make your browser window narrower than 550 pixels, the logo at the top will now get smaller to fit in the window, instead of being cut off (so will the other images).
img { max-width: 100%; }
Please note that flexible images will only get smaller on the rendered page. Your images will never be displayed larger than their actual dimensions (unless, of course, you are specifically trying to do so).
Clear the Footer
For this particular layout, there’s going to be lots of floating going on, so before we get started, we’re going to clear the footer so it’s out of the way. We’ll also add a border around it just so there’s a visual definition between the footer and the text above it.
#footer { clear: both; border: 1px solid #666; }
Add Page Margins
Next, we’re going to add margins on the page. All of the page content is in a div with the id of “content”, so we’ll use that to do the margins.
One of the key components of making a site responsive is to use percentages instead of pixels for any horizontal measurements. This is what allows all the elements on the page to expand and contract as we change the size of the browser window.
We’re going to set the width of the content div to 93%. Percentages are always in relation to the containing element, which in this case is the body. So our content div will be a width of 93% of the browser window regardless of the width of the window. The left/right margins are set to auto so that they split the remaining width of the window (so each margin is half of 7%).
Since it’s a percentage, as the browser gets narrower, the margins also get narrower.
How did I choose the number 93%? I just tried a few different numbers until it looked okay. Designing in the browser makes it easy.
The top and bottom margins for the content div are set to 0 and 10px. You can generally use pixels for vertical margins, as they don’t need to be flexible.
#content { width: 93%; margin: 0 auto 10px; }
Navigation: Vertical
We’re using a mobile-first approach to this exercise, so we’re going to start off by making the design look good at the narrowest width, and then work outward to wider widths.
Many phones are 320 pixels wide, so that’s a good place to start. If you’re using Safari, it has a minimum window width of about 400 pixels (it won’t let you make the browser window narrower than that), and for the purposes of this exercise, it’s okay to use that as your starting point.
Our navigation is coded as an unordered list, so it doesn’t currently look very navigation-like. We’re going to make it into a vertical navigation similar to what you see on a lot of mobile-sized websites.
The first thing we’re going to do is change the display of the list items from list-item to block, which gets rid of the bullets, and then we’ll set the padding on the ul to 0 to get rid of the default left margin.
nav ul li { display: block; } nav ul { padding: 0; }
Next, we’re going to make it look more navigation-like by putting a border around each list item, adding some padding, and center-aligning each list item.
nav ul li { border: 1px solid #666; padding: 5px 0; text-align: center; }
Navigation: Horizontal
That looks good at a narrow browser width, but when we start making the browser window wider, it looks funky to have those wide boxes with just a little text in the middle.
So when the window gets wider, we’re going to have the navigation change to horizontal.
This is going to be our first media query. Media queries are what make responsive design awesome.
The best way to think of a media query is that it’s a query, a question. It’s an if/then statement. If the query is true, render the CSS inside the query. If the query is not true, ignore the CSS inside the query.
In other words, if the query is true, the page is using different pieces of CSS (and thus will look different) than if the query is not true. The same page, the same code, different look.
The query is the first line of what you see in the code block below. After the actual query, you have an opening curly bracket. Then, there’s all the CSS, and after that there’s the closing curly bracket to end the query. Since both the query and the CSS use curly brackets, you have to be extra careful to make sure they match up and you don’t have extra curly brackets mucking things up.
Your media query always starts with @media.
After that, the word “screen” is the first query, telling the browser that the CSS should only apply if the page is being displayed on a screen (as opposed to print). For the purposes of responsive design, your media queries will almost always have screen as the first part of the query.
Next the word “and” to say that both screen and the next part of the query must be true in order for the entire query to be true.
The second part of the query is going to be enclosed in parenthesis. It starts with a feature. In this case, min-width refers to the size of the display area (the browser window). After that, there’s a colon, and then the value. So the entire phrase, in this case, is asking whether the browser window is a minimum width of 700 pixels.
If both parts of the query — screen and min-width: 700px — are true, then the CSS inside the query will be rendered.
If either part is not true, then the CSS inside the query will not be rendered.
I’m going to repeat that again because it’s really important: if the browser window is a minimum of 700 pixels wide (700 or greater), then the CSS will be rendered. If the browser window is narrower than 700 pixels, the CSS inside the media query will simply be ignored.
What we’re doing on our demo page is saying that if the browser window is 700 pixels or wider, we want the navigation to be horizontal instead of vertical. To do this, we’re changing the display of the list items from block to inline, and then centering the entire ul within the content area.
Why did I choose 700 pixels rather than some other width? I simply figured out the browser width at which the navigation items all fit on one line horizontally, and then added a bit extra for good measure.
@media screen and (min-width: 700px) { nav ul li { display: inline; } nav ul { text-align: center; } }
Navigation: Add Some Padding
Our navigation looks decent enough at any width wider than 700 pixels, but as we make the browser even wider, we have room to allow us to add extra padding to the list items. I chose 900 pixels as a good point at which to make this happen.
@media screen and (min-width: 900px) { nav ul li { padding: 5px 2%; } }
Feature Photo & Wrapping Text
We’re next going to take a look at the feature photo, in the Primary Content section. We’re going to go back and start out with our browser at the narrowest width. The photo fills the entire width of the browser window.
As we make the browser window wider, at some point the window is wider than the photo, leaving empty space next to the photo. We’re going to wrap the text around the photo to take advantage of the space.
To do this, we’re going to tell the browser that once the window is wide enough, it should size the image at 60% of its containing element.
This media query says that if the browser window is a minimum width of 450 pixels, then render the CSS: make the image 60% of the containing element, float it to the left, and give it a right margin of 3%.
How did I pick these numbers? I tried out a few different numbers, and figured out what looked good.
The photo, by the way, is from a trip I took to Seattle earlier this year.
@media screen and (min-width: 450px) { .feature-photo { margin-right: 3%; width: 60%; float: left; } }
Two Columns
The text wrapping around the photo worked really well for the middle range of browser window widths. However, as we make the browser window even wider, we get to a point where the 60% is wider than the actual width of the image. Images can’t be larger than their actual dimensions, so the photo is displayed at actual size, and the rest of the 60% is just empty space.
So what we’re going to do next is have the content split into two columns. We’re going to make this happen when the browser is a minimum of 800 pixels, which again I’ve picked by trying different numbers until I found a spot that worked out well.
In the HTML, the content is split into two divs, with ids of “primary” and “secondary” (matching the headlines, natch).
We’re going to set the primary div to be 60% of its containing element (the content div). Then the secondary div is going to be 38%, leaving us a couple spare percents for padding.
(Okay, that was a little bit of math, sorry. You have to subtract 60 from 100 to find out how much space you have left over for the other column.)
The primary div will float to the left, the secondary div to the right. We’ll add a left border and a little left padding on the secondary div so that there’s a line between the two columns.
In case you had any doubt that responsive design is easy, this is the evidence: you only need these few lines of CSS to make your layout change from one to two columns. How awesome is that?
@media screen and (min-width: 800px) { #primary { width: 60%; float: left; } #secondary { width: 38%; float: right; padding-left: 1%; border-left: 1px solid #666; } }
Photo Gallery: Two Rows
We haven’t done anything terribly complicated yet. So let’s bring it up a notch and see what we can do with a photo gallery.
Our gallery has four photos. Or rather, four of the same photo, because I really like this one; it’s of my trip to Fallingwater last year. If you’re making your own photo gallery like this, you just need to make sure your image files for the gallery are all cropped to the exact same dimensions so they’ll line up.
We’re going to start at our narrowest browser width again.
Those photos are taking up a lot of space, so we’re going to make them smaller so they can be in two rows of two.
Our HTML for this section is four divs, each of which contains a photo and caption. All four divs have a class of “photo”. Every other div has a class of either “photo-odd” or “photo-even”. The last div has an additional class of “photo-last”.
First, we’re going to give each photo div a width of 47%, slightly less than half. That gives us some white space in between. Keep in mind the percentage is of the containing element.
The photo-odd divs (#1 and #3 in the HTML) are floated to the left, and the photo-even divs (#2 and #4 in the HTML) are floated to the right.
The photo-odd divs are also cleared so that photo #3 will start fresh with its floating. Otherwise, due to differing caption lengths, the bottom row of photos wouldn’t line up.
.photo { width: 47%; } .photo-odd { clear: both; float: left; } .photo-even { float: right; }
Photo Gallery: One Row
That works out well when the browser window is very narrow, but as I make it wider, the photos at some point stop getting bigger. Remember, we had made our image files the dimension that’s the largest we want the images to appear.
So when the browser is a minimum width of 600 pixels, we’re going to have the photos display in one row instead of two.
To do this, we’re setting the width of each photo to 23% (a little less than 1/4). How did I pick 23%? I just tried different numbers until I figured out what looked good.
And then you need to do a very tiny bit of math again here (very sorry), to determine how big the margins between the photos should be. Four photos at 23% add up to 92%, leaving us with 8% left.
We have three margins, so we need to figure out a third of 8%. If you use a calculator, you’ll get a number with a whole lot of digits on the end. Unless you’re really obsessive, it’s okay to ignore those. I’ve rounded down to 2.65% to make sure the margins fit.
If you happen to forget and round up instead of down, there won’t be enough space for your fourth image and it will wrap onto the next line. You’ll figure things like that out when they happen. The awesome thing about designing in the browser is that if something turns out not to work right, you can easily try different things until you figure out how to make it look like you want.
All four photo divs are given a width of 23% and a right margin of 2.65%. However, just after that, we give the fourth photo, via the photo-last class, a right margin of 0, because we want it to go all the way to the right edge of the content area.
We’re floating the photo divs to the left, except the fourth photo, which we’ll float to the right, so it’s flush up against that right edge of the content area.
There’s one little tricky bit here. Remember in the last section, we cleared the photo-odd divs so that the second row of photos lined up? That CSS is still in effect, so we need to override it here, otherwise our photos will be on two rows. All we need to do is add clear:none on the photo class so that none of the photo divs will clear.
@media screen and (min-width: 600px) { .photo { width: 23%; margin-right: 2.65%; float: left; clear: none; } .photo-last { margin-right: 0; float: right; } }
Photo Gallery: In the Left Column on Two Rows
Our photos look good in one row like that, up until the point (800 pixels) where the content above it splits into two columns. That messed up our whole design, and now our photos aren’t in a row any more.
So at 800 pixels, which is the minimum width where we already told the browser to split the content into two columns, we’re going to have the photo gallery be only in the left column, rather than going all the way across the page.
To make that happen, we’ll do a media query for a minimum width of 800 pixels, the same as where we split to the two columns. We’re telling the gallery div (containing all the photo divs) to be a width of 60% and float to the left.
@media screen and (min-width: 800px) { #gallery { width: 60%; float: left; } }
That put our photos right where we wanted them in the left column, but now they’re tiny, so that’s a problem.
To split the photos into two rows, we’re going to use the exact same CSS as we used a few sections back when we first applied styles to the gallery and made it into two rows. This time the same CSS is in a media query for a minimum width of 800 pixels.
@media screen and (min-width: 800px) { .photo { width: 47%; margin-right: 0; } .photo-odd { clear: both; float: left; } .photo-even { float:right; } }
You’re probably wondering, since we’re using the same code over again, can’t we combine them somehow? Unfortunately, we can’t, because we need the media queries to render in the correct order through the stylesheet. There was something else going on in between when we first used this CSS and when we’re reusing it now.
Photo Gallery: One Row Again
Our gallery looks great at 800 pixels and as we start to make our browser a bit wider, but again there’s a point where the photos stop getting bigger. So at a minimum width of 1000 pixels, we’re going to have the photos go back to one row so they can use all the space.
The style is going to be exactly the same as when we made the one row of photos at 600 pixels. So although the media query is a different min-width, the CSS inside the query is exactly the same.
@media screen and (min-width: 1000px) { .photo { width: 23%; margin-right: 2.65%; float: left; clear: none; } .photo-last { margin-right: 0; float: right; } }
Are we done?
Yes we are! Congratulations, you now have a responsive website.
Certainly, you have a lot left to learn. But you should now have a solid understanding of what’s going on when a responsive site is being responsive.
Resources
If you want to learn all the important stuff in one go, I suggest you get the book Responsive Web Design by Ethan Marcotte. He invented responsive design and is super-smart.
And these are just a few websites you might find useful.
- Mediaqueri.es – inspirational websites using media queries and responsive web design
- Smashing Magazine (posts tagged responsive design)
- .net Magazine (articles tagged responsive design)
You’ll find plenty of other stuff on the web, so just look around.
But the absolute best way to learn more is to keep trying actual code to see what it does. Don’t feel like you need to practice by building whole websites. Just whip out your text editor and put a few things together and see how it flies in a browser. Do things that are outrageous; nobody will ever see your practice files unless you get the brilliant idea to make them into a tutorial to post online, like I just did.
Thank you for this, I have followed and searched for lots of responsive design tutorials both text and YouTube but this (yours) is by far the best and easiest to follow – so thank you Clarissa @chiswickman