How to Create a Responsive Website Layout

Web Development Post by Christopher Spicer
Responsive Website Layout

Excellent content is what draws visitors to your website. But excellent page layout is what ensures that your visitors are able to find and engage with that content.

Let’s face it. We live in a high-speed world. You may have spent days poring over every word and every image that appears on your site. But visitors will determine in seconds whether to stay on your page or hit the back button. A decision that is made or broken in the time it takes them to glance at a few pictures or scan a few lines of text.

First impressions are critical. The presentation of your website makes an impact on visitors long before they’ve explored the depth of your content. And a good page layout is an essential element of that presentation.

So what is layout? Simply stated, layout is the organizational framework that provides structure to the information presented on your page. It is the use of size, position, spacing, and contrast to define relationships between individual design elements. Okay, so what is a good layout? Well, that is a bit more nuanced. But a good layout:

  • Structures information in a way that is logical and intuitive
  • Groups related elements and separates unrelated elements
  • Establishes a clear hierarchy that focuses attention on the most important elements first
  • Maintains consistent design elements to build a cohesive experience
  • Creates a natural flow and sense of balance between elements
  • Remains functional and aesthetic in all its variations

This article, which is the first in a series of web development tutorials, will guide you through the process of creating basic layout elements that you can use to structure your web pages in an endless variety of configurations. Step by step, we’ll transform concepts into code before ultimately combining these examples into complete web page demonstrations.

Skip Ahead

Looking for something specific? Select a topic to read more:

Document Structure

Let’s start by setting up the standard template for our HTML document:

HTML

<!DOCTYPE html> <html lang="en-US"> <head> <title>My Page</title> <meta charset="UTF-8"> <!-- HTML Head Code --> <style> /* CSS Code */ </style> </head> <body> <!-- HTML Body Code --> </body> </html>

We begin with the <!DOCTYPE html> declaration to identify that our document uses the HTML5 specification. This allows us to utilize the complete set of semantic elements not available in previous versions of HTML.

Next we place the <html lang="en-US"> element to establish the root of our document and to specify the language as United States English (feel free to change the value of this attribute if you’re defaulting to a different language).

The first element inside the <html> root is the <head>. This element will contain all of the document metadata (information that is not visually rendered on the page, but is used by web browsers and search engines). Here we insert the <title> element to specify a title for our document. We insert the <meta charset="UTF-8"> element to specify that our document uses UTF-8 encoding (typical for web pages). And we insert the <style> element to contain all of our CSS rules.

The second element inside the <html> root is the <body>. This element will contain all of the document content (information that is visually rendered on the page).

HTML documents can be created with any text editor of your choice, including basic applications like Notepad. To create a working web page, simply save your text document with UTF-8 encoding and use the .htm file extension.

To customize any of the web page demonstrations presented in this article, first use your web browser to save a local copy of the document on your computer. Then open the file in your text editor to add, remove, and modify code to create your own web design masterpiece.

Naming Convention

It’s worthwhile to note the standard CSS naming convention that will be used in the upcoming examples and demonstrations. All CSS rules will take the form of .module for component classes and .module_submodule for subcomponent classes, with -modifier suffixes added to each where multiple variations are required. Classes that are uniquely defined for a specific part of the document will be preceded by a #section selector.

This system is one that I have found to be clear, concise, and versatile. However, there is absolutely no requirement that you adopt it as well. You should feel empowered to use any naming convention that appeals to you.

Responsive Design

There was a time when the internet was a realm accessible only to computers. It was the 1990s. Cell phones were the size of small pets. America Online CDs seemed to rain from the heavens. And across the country homes resonated with the delightful hissing and cracking of 56k modems dialing up to the web.

Fast-forward twenty years and nearly every device with a screen, from the pocket-sized to the wall-consuming, is internet-capable. And this presents a unique challenge to web developers. How do we construct page layouts that look good on all devices, from a 320-pixel-wide phone to a 3,840-pixel-wide television?

We could create unique layouts dedicated to every possible combination of screen size and resolution. But given the hundreds (perhaps thousands) of difference screen sizes and resolutions currently in use, with new configurations entering the market each year, that would seem a near-impossible task.

Fortunately there is a better option. Rather than designing multitudes of fixed layouts for specific devices, we instead design a single fluid layout that dynamically adjusts to all devices. This technique is called “responsive design”. And it allows us to create a single layout that looks great at any size and any resolution.

The key to developing a responsive design is the creation of a flexible layout that resizes, repositions, and even hides or shows elements based on the size and resolution of the screen.

Let’s take a look at how the same fluid layout might appear on different devices:

Responsive Website Layout as Viewed on a Phone

Phone

Responsive Website Layout as Viewed on a Tablet

Tablet

Responsive Website Layout as Viewed on a Computer

Computer

Now that we understand the basic concept of responsive design, let’s use it to start building our layout!

Viewport

To create a responsive layout, we must first instruct the web browser exactly how to control the width and scale of our page. We do this by inserting an additional line of code into the <head> of our document:

HTML

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

This tag sets the width of the page equal to the screen width of the device. It also sets the initial scale of the page so that 1 CSS pixel equals 1 device-independent pixel (commonly abbreviated as “dip” or “dp”).

Box Sizing

To create a responsive layout, we must also instruct the web browser exactly how to control the size of the elements that appear on our page.

By default, browsers use the “content box” model, which calculates size based only on the dimensions of an element’s content. Because this method of calculation does not include an element’s borders or padding, it may produce some unexpected results when we create our layout.

Imagine, for example, that we want to position two equally-sized elements next to each other. Naturally, we define the width of each element to be 50%. However, if these elements have borders or padding, then the total width of each element (calculated as: defined width + borders + padding) becomes greater than 50%. And suddenly we discover that our elements are slightly too wide to be positioned next to each other.

Fortunately there is a simple solution. We instead tell the browser to use the “border box” model, which does include borders and padding when calculating the size of an element. Therefore, the defined width matches the total width and produces the results that we expect.

To make life even easier, let’s also reset the default margins, borders, and padding to 0. This way we can consciously add these properties to specific elements where desired, without being surprised by default styles that may vary from browser to browser.

Here is the code to use border box sizing and reset the default styles:

CSS

* { box-sizing: border-box; margin: 0; border: 0; padding: 0; }

Page Width

As we start to plan the basic layout of our page, it’s natural to feel compelled to fill every available pixel with content. And for some minimalist, image-heavy compositions this approach produces great results.

Most compositions, however, are likely to include a number of design elements like text, forms, images, videos, and more. As our layout becomes more varied and complex, we find that it actually becomes advantageous not to stuff every nook and cranny with content.

By leaving some empty space (commonly called “negative space” or “whitespace”) around these design elements, we significantly increase the overall readability of our page. Counterintuitive though it may seem, the presence of this empty space creates a sense of contrast that actually draws more attention to the space that is filled with content.

One of the best things we can do to add some breathing room to our layout is to constrain the page width. On large screens, this prevents the content area from extending all the way to the edge of the viewport. The additional space on both sides of our page acts as a natural separator, immediately drawing the eye towards the content in the center.

Let’s take a look at two examples:

Unconstrained Page Width

Unconstrained Page Width

Constrained Page Width

Constrained Page Width

Notice how the content area appears to stand out more in the second layout than in the first?

Constraining the page width also allows us to optimize the line length of our text area. A number of studies have explored the topic of ideal line length, most of them indicating that maximum readability occurs between approximately 50 and 75 characters per line. Much shorter than that, and readers are forced to move their eyes back and forth at an unpleasant pace. Much longer than that, and it becomes difficult to transition from the end of one line to the beginning of the next.

While these guidelines are relatively simple to apply in fixed mediums like print, fluid mediums like web design often require a bit more complexity to maximize readability. In practice, sizing text-heavy layouts to approximately 60 to 80 characters per line on large screens, and 40 characters per line on small screens, allows readers to maintain a comfortable rhythm across all devices.

Now that we understand exactly how we want to constrain our content area, let’s create some code to make it so!

First we construct a simple section in HTML that contains a heading and some body text:

HTML

<section class="page"> <h1 class="heading"> Heading 1</h1> <p class="text"> Paragraph</p> </section>

Since we’re using the HTML5 specification, we can utilize newer semantic markup elements like <section> for sections, as well as older semantic markup elements like <h1> through <h6> for headings and <p> for paragraphs. Including proper markup elements is an essential component of search engine optimization (commonly abbreviated as “SEO”), as it provides contextual meaning to our content in a way that is readable by search algorithms.

Next we use CSS to style this section:

CSS

.page { max-width: 640px; margin: 0 auto; } @media (min-width: 960px) { .page {max-width: 960px;} } .heading {font: bold 32px / 1.5 sans-serif;} .text {font: 16px / 1.5 sans-serif;}

We control the width of our content area with a class named <page>. We start with the max-width: 640px property. This limits the maximum width of our content area to 640 pixels. Then we include the margin: 0 auto property. This horizontally centers our content area within the viewport.

This layout looks pretty good on small and medium screens. But on large screens, our content area seems a bit narrow. So let’s increase the maximum width to 960 pixels, but only on large devices.

To accomplish this, we introduce the @media rule (commonly called a “media query”). This rule contains instructions that are applied only when the conditions of the rule are met.

In this case, the instruction is to set the maximum width of our content area to 960 pixels. And the condition is that the device must have a minimum width of 960 pixels. You’ll notice that the media query is placed after the initial class definition. This gives the media query precedence over the initial class definition (but only when the condition of the rule is met). So what we have is a content area with a maximum width that is limited to 640 pixels. Unless the device has a minimum width of 960 pixels. Then the maximum width of our content area is limited to 960 pixels.

The technique of using media queries to create responsive layout elements is something we will explore further when we construct our grid.

Finally we create two additional classes to control the font size and style of our heading and body text.

Section Padding

Now that we've learned how to use whitespace to add some breathing room around the content area of our page, let's see how to use it within that content area.

Even the simplest web pages are likely to contain multiple groups of related information. These groups are called “sections”. And keeping them clearly defined is an important part of creating a well-structured page.

Structure is all about the relationships that exist between different design elements. And one of the best things we can do to establish these relationships is to add a little whitespace between sections.

The human eye naturally perceives elements that are positioned closely together as being more connected than elements that are positioned farther apart (a phenomenon known as the Gestalt principle of proximity). And this phenomenon is one that we can readily use to add clarity to the structure of our page.

Let’s take a look at two examples:

Unpadded Sections

Unpadded Sections

Padded Sections

Padded Sections

In the first example, there is very little visual distinction between the two top-level sections. Only the header font size gives any indication at all that different sections even exist.

But in the second example, there is much more visual distinction. The extra whitespace between the two top-level sections creates a strong visual relationship that works in harmony with the header font size. Even at first glance, the hierarchy of the page is perfectly clear.

A powerful visual effect, achieved with nothing more than the proper use of a little empty space. Now let's create some code to make it so:

Single-Level Sections

Let's start with a simple document structure containing several of top-level sections.

As before, we construct simple sections in HTML that each contains a heading and some body text:

HTML

<section class="page section"> <h1 class="heading"> Heading 1</h1> <p class="text"> Paragraph</p> </section> <section class="page section"> <h1 class="heading"> Heading 2</h1> <p class="text"> Paragraph</p> </section> <section class="page section"> <h1 class="heading"> Heading 3</h1> <p class="text"> Paragraph</p> </section>

To create whitespace, we add 8 pixels of padding around each section as well as 8 pixels of padding around each heading and paragraph:

CSS

.section {padding: 8px;} .heading { padding: 8px; font: bold 32px / 1.5 sans-serif; } .text { padding: 8px; font: 16px / 1.5 sans-serif; }

These values combine to leave 32 pixels of whitespace between sections and 16 pixels of whitespace between headings and paragraphs.

Multiple-Level Sections

Now let's add a little more depth to our document structure by creating several top-level sections that are further divided into several subsections.

As before, we start with a <section> element to establish a top-level section. First we insert a <header> element containing a top-level <h1> heading and some body text. This begins each section with some introductory information. Next we create our subsections by inserting nested <section> elements, each with a lower-level <h2> heading and some more body text:

HTML

<section class="page section-1"> <header class="section-2"> <h1 class="heading-1"> Heading 1</h1> <p class="text"> Paragraph</p> </header> <section class="section-2"> <h2 class="heading-2"> Heading 1-1</h2> <p class="text"> Paragraph</p> </section> <section class="section-2"> <h2 class="heading-2"> Heading 1-2</h2> <p class="text"> Paragraph</p> </section> </section> <section class="page section-1"> <header class="section-2"> <h1 class="heading-1"> Heading 2</h1> <p class="text"> Paragraph</p> </header> <section class="section-2"> <h2 class="heading-2"> Heading 2-1</h2> <p class="text"> Paragraph</p> </section> <section class="section-2"> <h2 class="heading-2"> Heading 2-2</h2> <p class="text"> Paragraph</p> </section> </section>

Once again, we add 8 pixels of padding around each subsection as well as 8 pixels of padding around each heading and paragraph. But this time we also add 16 pixels of vertical padding around each top-level section:

CSS

.section-1 {padding: 16px 0;} .section-2 {padding: 8px;} .heading-1 { padding: 8px; font: bold 32px / 1.5 sans-serif; } .heading-2 { padding: 8px; font: bold 24px / 1.5 sans-serif; } .text { padding: 8px; font: 16px / 1.5 sans-serif; }

These values combine to leave 64 pixels of whitespace between sections, 32 pixels of whitespace between subsections, and 16 pixels of whitespace between headings and paragraphs.

And this process is completely modular. In theory, you can continue this technique of adding vertical padding to create as many levels of subsections as you wish. In practice, however, it is considered best not to include more than three levels of subsections, as an excessively complex hierarchy can become confusing to the reader.

Grid Layout

So far we have structured our page layout with a purely vertical flow – each new block of content has been placed immediately below its predecessor. But our design can (and in most cases should) include horizontal flow as well.

To create a layout that allows us to build in both directions, we subdivide the page into rows and columns that collectively form a system known as a “grid”. Along these rows and columns we can arrange blocks of content in an endless number of ways. By its nature, a grid is both versatile and modular. It provides the creative freedom to alter the balance and flow of a page with great flexibility, while simultaneously maintaining a sense of consistency and purposeful design.

Let's take a look at the different components that make up a grid:

Anatomy of a Grid

Anatomy of a Grid

  • Margins are the negative spaces that surround the entire content area.
  • Gutters are the negative spaces that separate individual columns.
  • Flowlines are horizontal subdivisions that separate individual blocks of content.
  • Columns are vertical subdivisions of the content area.
  • Modules are blocks of content defined by the intersection of flowlines and columns.

In this tutorial we will construct our grid using the CSS Flexible Box Module (commonly called “flexbox”). Before this technique was introduced, web developers were forced to use tables or floated elements to arrange complex layouts. However, neither tool was ever intended to be used in this way, and both approaches came with limitations. Flexbox, on the other hand, is a purpose-built layout tool designed specifically for page layout.

Grid Container

First we must construct a container to hold all of our individual grid modules.

We define our container with a class called grid:

CSS

.grid { display: flex; flex-flow: row wrap; justify-content: flex-start; }

We start with the display: flex property. This applies flexbox behavior to our container. Then we include the flex-flow: row wrap property. The value of this property declares two things. First, that the main axis of flow is in the horizontal direction (by implication, the cross axis direction of flow is in the vertical direction). Second, that when flexible elements exceed the length of a single line they should continue onto the next line. Finally we include the justify-content: flex-start property. This establishes a left-to-right flow where flexible elements begin aligned to the left edge of our container.

For even greater versatility, we can create three variations of our grid class for left-aligned, right-aligned, and center-aligned layouts:

CSS

.grid-left { display: flex; flex-flow: row wrap; justify-content: flex-start; } .grid-right { display: flex; flex-flow: row wrap; justify-content: flex-end; } .grid-center { display: flex; flex-flow: row wrap; justify-content: center; }

Grid Modules

Now that we've defined our grid container, let's start to populate it with modules.

We know that grids are vertically subdivided into columns. And as the designer, it is entirely up to you to select the number of columns that works best for your layout. But exactly how many columns should you choose?

There is no universal answer. It is entirely dependent on the layout you wish to design. Throughout the web, two, three, four, and six-column grids are all quite common. However, it is perhaps the twelve-column grid that is most widely used. This configuration is particularly versatile because it not only supports twelve-column layouts, but two, three, four, and six-column layouts as well. Because of its ubiquity, we will use a twelve-column grid in all of the examples and demonstrations in this article.

We also know that modules are not restricted to the width of a single column. They are free to span any number of columns. And this provides us with many possible module widths.

Let’s take a look at the available module widths in a twelve-column grid:

Column Span Column Width
1 Column 8.33%
2 Columns 16.66%
3 Columns 25%
4 Columns 33.33%
5 Columns 41.66%
6 Columns 50%
7 Columns 58.33%
8 Columns 66.66%
9 Columns 75%
10 Columns 83.33%
11 Columns 91.66%
12 Columns 100%

Now the CSS!

To accommodate every possible variation of our layout, we need to create a class for each available module width:

CSS

.grid_mod-1 { flex: 0 0 auto; width: 8.33%; } .grid_mod-2 { flex: 0 0 auto; width: 16.66%; } .grid_mod-3 { flex: 0 0 auto; width: 25%; } ... .grid_mod-12 { flex: 0 0 auto; width: 100%; }

We start the name of each class with grid_mod (short for “grid module”). This is followed by a numerical modifier corresponding to the number of columns that module is set to span. 1 / 12 * 100% = 8.33%, 2 / 12 * 100% = 16.66%, 3 / 12 * 100% = 25%, and so on.

We start each module with the flex: 0 0 auto property. This declares that each module conforms to a defined width (rather than growing or shrinking to fill or fit the available space). Next we include the width property to establish that defined width.

You'll notice that we've intentionally rounded down the percentage values. The reason is that rounding up would, in some cases, produce modules that are slightly too wide to fit the grid.

Take, for example, a six-column layout. Six modules, each with a width rounded up to 16.67%, would combine to be 100.02% the width of the grid container (6 * 16.67% = 100.02%). Because the combined width is slightly larger than the available width, this would only allow the first five modules to exist on the top line, forcing the sixth module to the next line. We avoid this issue by simply rounding down (6 * 16.66% = 99.96%).

For you perfectionists out there, feel free to use as many decimal places as you like. But there’s no need to get carried away. Even on large screens, two or three decimal places is enough to provide sub-1-pixel accuracy.

And now the HTML!

As before, we construct simple sections in HTML that each contains a heading and some body text:

HTML

<div class="page grid"> <section class="section grid_mod-4"> <h1 class="heading"> Heading 1</h1> <p class="text"> Paragraph</p> </section> <section class="section grid_mod-4"> <h1 class="heading"> Heading 2</h1> <p class="text"> Paragraph</p> </section> <section class="section grid_mod-4"> <h1 class="heading"> Heading 3</h1> <p class="text"> Paragraph</p> </section> </div>

To create our grid container, we wrap all of the sections in a <div> element that we style with the page and grid classes. To transform each section into a grid module, we assign it the section and grid_mod-4 classes. In our twelve-column-layout, this produces modules that are each 33.33% the width of its container (4 / 12 * 100% = 33.33%).

And there you have it! A three-column grid layout that scales responsively to fit screens of all sizes. But there’s no need to stop there. You can experiment with different combinations of module widths and quantities to achieve any design that you like.

Media Queries

So far we've created a grid with a fixed number of columns that scale to fit the screen. But we can take our responsive design one step further by allowing the number of columns to be fluid as well.

This way, we allow our three-column layout, which looks great on large screens, to progressively collapse to a two-column layout on medium screens, and a one-column layout on small screens. Remember how we used a media query to control the width of our page? We can also use them to control the column span of each module. And we do this by setting breakpoints – defined screen sizes where control is handed from one media query to another.

This raises an obvious question: with so many available screen sizes and resolutions, how do we begin to know where to set these breakpoints? You'll recall that the basic principal of responsive design is to create a layout that looks great, not only on specific devices at specific sizes, but on all devices at all sizes. With that in mind, it is the layout, not the size of particular devices, that we want to drive our breakpoints.

As the designer, it is entirely up to you to select the sizes where the layout should change. For the examples and demonstrations in this article, we will use the following breakpoints:

Device Size Viewport Width
Small 479px and Below
Medium 480px to 959px
Large 960px and Above

To apply this responsive behavior to our grid modules, we create three sets of grid_mod classes:

CSS

/* Small Devices */ @media (max-width: 479px) { .grid_mod-sm-1 { flex: 0 0 auto; width: 8.33%; } .grid_mod-sm-2 { flex: 0 0 auto; width: 16.66%; } .grid_mod-sm-3 { flex: 0 0 auto; width: 25%; } ... .grid_mod-sm-12 { flex: 0 0 auto; width: 100%; } } /* Medium Devices */ @media (min-width: 480px) and (max-width: 959px) { .grid_mod-md-1 { flex: 0 0 auto; width: 8.33%; } .grid_mod-md-2 { flex: 0 0 auto; width: 16.66%; } .grid_mod-md-3 { flex: 0 0 auto; width: 25%; } ... .grid_mod-md-12 { flex: 0 0 auto; width: 100%; } } /* Large Devices */ @media (min-width: 960px) { .grid_mod-lg-1 { flex: 0 0 auto; width: 8.33%; } .grid_mod-lg-2 { flex: 0 0 auto; width: 16.66%; } .grid_mod-lg-3 { flex: 0 0 auto; width: 25%; } ... .grid_mod-lg-12 { flex: 0 0 auto; width: 100%; } }

Each set is contained inside of a media query that corresponds to a particular range of screen sizes. Grid modules with the -sm modifier are applied to small screens (479 pixels and below). Grid modules with the -md modifier are applied to medium screens (480 to 959 pixels). And grid modules with the -lg modifier are applied to large screens (960 pixels and above).

As before, we transform each section into a grid module:

HTML

<div class="page grid"> <section class="section grid_mod-sm-12 grid_mod-md-6 grid_mod-lg-4"> <h1 class="heading"> Heading 1</h1> <p class="text"> Paragraph</p> </section> <section class="section grid_mod-sm-12 grid_mod-md-6 grid_mod-lg-4"> <h1 class="heading"> Heading 2</h1> <p class="text"> Paragraph</p> </section> <section class="section grid_mod-sm-12 grid_mod-md-6 grid_mod-lg-4"> <h1 class="heading"> Heading 3</h1> <p class="text"> Paragraph</p> </section> </div>

But this time, instead of a grid modules being fully defined by a single grid_mod class, we assign a set of three grid_mod classes to control the behavior on small, medium, and large screens. Now, for the low price of a just a little extra code, we have a fully responsive grid layout that is able to resize and restructure columns to fit screens of all sizes.

In this example, we’ve created modules that are 100% wide on small screens, 50% wide on medium screens, and 33.33% wide on large screens.

Putting it All Together

We've covered a lot of ground in this article – the principles of responsive design, controlling page width, creating whitespace between sections, and designing a fluid grid. So far we've looked at simple examples of how to apply these techniques individually. But now it's time to turn you loose on the world so that you can apply these techniques holistically to create your own complete web pages.

To help you with that next step, take a look at the six demonstrations below. Click on each one to open it in a new window. Once it is open, the “View Source” functionality of your web browser will allow you to see the page code. To use a demonstration as a template, first use your web browser to save a local copy of the document on your computer. Then open the file in your text editor to experiment with adding, removing, and modifying code.

And in no time at all, you'll find yourself ready to kick off the training wheels and create your own web design masterpieces entirely from scratch!

Demo 1

Sample “Home” page with a one and three-column layout:

See Demo

Demo 2

Sample “About” page with a one, two, and three-column layout:

See Demo

Demo 3

Sample “Product” page with a one, two, three, and four-column layout:

See Demo

Demo 4

Sample “Service” page with a one and three-column layout:

See Demo

Demo 5

Sample “Portfolio” page with a one and three-column layout:

See Demo

Demo 6

Sample “Blog” page with a one and three-column layout:

See Demo