Historic website layouts

HTML is fundamentally responsive. If you create a web page containing text and resize the browser window, or display the page on a device with a smaller screen, then the browser will automatically reflow the text to fit the window.
This is called a liquid layout.
The problem with this layout, though, is that the site would look squashed on smaller screens (as seen below) and have unreadably long line lengths on larger ones.

liquid layout

The alternative is to create a fixed width layout, which sets elements to a fixed size in pixels.
The problem with this approach is that you will get a horizontal scrollbar on screens smaller than the site width (as seen below), and lots of white space at the edges of the design on larger screens.

fixed layout
Flexible layout before responsive design

A number of approaches were developed to try to solve the downsides of the liquid or fixed-width methods of building websites. In 2004 Cameron Adams wrote a post entitled Resolution dependent layout, describing a method of creating a design that could adapt to different screen resolutions. This approach required JavaScript to detect the screen resolution and load the correct CSS.

Responsive design

The term responsive design was coined by Ethan Marcotte in 2010 and described the use of three techniques in combination.

  • The first was the idea of fluid grids, something which was already being explored by Gillenwater, and can be read up on in Marcotte's article, Fluid Grids (published in 2009 on A List Apart).
  • The second technique was the idea of fluid images. Using a very simple technique of setting the max-width property to 100%, images would scale down smaller if their containing column became narrower than the image's intrinsic size, but never grow larger. This enables an image to scale down to fit in a flexibly-sized column, rather than overflow it, but not grow larger and become pixelated if the column becomes wider than the image.
  • The third key component was the media query. Media Queries enable the type of layout switch that Cameron Adams had previously explored using JavaScript, using only CSS. Rather than having one layout for all screen sizes, the layout could be changed. Sidebars could be repositioned for the smaller screen, or alternate navigation could be displayed.
Media Queries

Responsive design was only able to emerge due to the media query. The Media Queries Level 3 specification became a Candidate Recommendation in 2009, meaning that it was deemed ready for implementation in browsers. Media Queries allow us to run a series of tests (e.g. whether the user's screen is greater than a certain width, or a certain resolution) and apply CSS selectively to style the page appropriately for the user's needs.

For example, the following media query tests to see if the current web page is being displayed as screen media (therefore not a printed document) and the viewport is at least 800 pixels wide. The CSS for the .container selector will only be applied if these two things are true.


                @media screen and (min-width: 800px) {
                    .container {
                      margin: 1em 2em;
                    }
                  }
                

You can add multiple media queries within a stylesheet, tweaking your whole layout or parts of it to best suit the various screen sizes. The points at which a media query is introduced, and the layout changed, are known as breakpoints.
Find out more in the MDN documentation for Media Queries.

Flexible grids

Responsive sites don't just change their layout between breakpoints, they are built on flexible grids. A flexible grid means that you don't need to target every possible device size that there is, and build a pixel perfect layout for it. That approach would be impossible given the vast number of differently-sized devices that exist, and the fact that on desktop at least, people do not always have their browser window maximized.

By using a flexible grid, you only need to add in a breakpoint and change the design at the point where the content starts to look bad. For example, if the line lengths become unreadably long as the screen size increases, or a box becomes squashed with two words on each line as it narrows.

In the early days of responsive design, our only option for performing layout was to use floats. Flexible floated layouts were achieved by giving each element a percentage width, and ensuring that across the layout the totals were not more than 100%. In his original piece on fluid grids, Marcotte detailed a formula for taking a layout designed using pixels and converting it into percentages.

target / context = result

For example, if our target column size is 60 pixels, and the context (or container) it is in is 980 pixels, we divide 60 by 980 to get a value we can use in our CSS, after moving the decimal point two places to the right.


                .col {
                    width: 6.12%; /* 60 / 980 = 0.0612 */
                  }
                

This approach will be found in many places across the web today, and it is documented here in the layout section of our Legacy layout methods article. It is likely that you will come across websites using this approach in your work, so it is worth understanding it, even though you would not build a modern site using a float-based flexible grid.

example of responsive design
Modern layout technologies

Modern layout methods such as Multiple-column layout,Flexbox, and Grid are responsive by default. They all assume that you are trying to create a flexible grid and give you easier ways to do so.

Multicol

The oldest of these layout methods is multicol — when you specify a column-count, this indicates how many columns you want your content to be split into. The browser then works out the size of these, a size that will change according to the screen size.


                .container {
                    column-count: 3;
                  }
                

If you instead specify a column-width, you are specifying a minimum width. The browser will create as many columns of that width as will comfortably fit into the container, then share out the remaining space between all the columns. Therefore the number of columns will change according to how much space there is.


                .container {
                    column-width: 10em;
                  }
                

Flexbox

In Flexbox, flex items will shrink and distribute space between the items according to the space in their container, as their initial behavior. By changing the values for flex-grow and flex-shrink you can indicate how you want the items to behave when they encounter more or less space around them.


                .container {
                    display: flex;
                  }
                

CSS grid

In CSS Grid Layout the fr unit allows the distribution of available space across grid tracks. The next example creates a grid container with three tracks sized at 1fr. This will create three column tracks, each taking one part of the available space in the container. You can find out more about this approach to create a grid in the Learn Layout Grids topic, under Flexible grids with the fr unit.


                .container {
                    display: grid;
                    grid-template-columns: 1fr 1fr 1fr;
                  } 
                
Responsive images

The simplest approach to responsive images was as described in Marcotte's early articles on responsive design. Basically, you would take an image that was at the largest size that might be needed, and scale it down. This is still an approach used today, and in most stylesheets, you will find the following CSS somewhere:


                img {
                    max-width: 100%;
                  }
                

There are obvious downsides to this approach. The image might be displayed a lot smaller than its intrinsic size, which is a waste of bandwidth — a mobile user may be downloading an image several times the size of what they actually see in the browser window. In addition, you may not want the same image aspect ratio on mobile as on desktop. For example, it might be nice to have a square image for mobile, but show the same scene as a landscape image on desktop. Or, acknowledging the smaller size of an image on mobile you might want to show a different image altogether, one which is more easily understood at a small screen size. These things can't be achieved by scaling down an image.

You can find a detailed guide to Responsive Images in the Learn HTML section here on MDN.

Responsive typography

An element of responsive design not covered in earlier work was the idea of responsive typography. Essentially, this describes changing font sizes within media queries to reflect lesser or greater amounts of screen real estate.

In this example, we want to set our level 1 heading to be 4rem, meaning it will be four times our base font size. That's a really large heading! We only want this jumbo heading on larger screen sizes, therefore we first create a smaller heading then use media queries to overwrite it with the larger size if we know that the user has a screen size of at least 1200px.


                html {
                    font-size: 1em;
                  }
                  
                  h1 {
                    font-size: 2rem;
                  }
                  
                  @media (min-width: 1200px) {
                    h1 {
                      font-size: 4rem;
                    }
                  }
                

We have edited our responsive grid example above to also include responsive type using the method outlined. You can see how the heading switches sizes as the layout goes to the two column version.

On mobile the heading is smaller:

responsive mobile

Using viewport units for responsive typography

An interesting approach is to use the viewport unit vw to enable responsive typography. 1vw is equal to one percent of the viewport width, meaning that if you set your font size using vw, it will always relate to the size of the viewport.


                h1  {
                     font-size: 6vw;
                   }   
                

The problem with doing the above is that the user loses the ability to zoom any text set using the vw unit, as that text is always related to the size of the viewport.
Therefore you should never set text using viewport units alone.

There is a solution, and it involves using calc(). If you add the vw unit to a value set using a fixed size such as em or rem then the text will still be zoomable. Essentially, the vw unit adds on top of that zoomed value:


                h1 {
                    font-size: calc(1.5rem + 3vw);
                  }  
                
The viewport meta tag

If you look at the HTML source of a responsive page, you will usually see the following ‹meta›tag in the ‹head› of the document.

                    ‹meta name="viewport" content="width=device-width,initial-scale=1"/›
                

This meta tag tells mobile browsers that they should set the width of the viewport to the device width, and scale the document to 100% of its intended size, which shows the document at the mobile-optimized size that you intended.

This meta tag exists because when the original iPhone launched and people started to view websites on a small phone screen, most sites were not mobile optimized. The mobile browser would, therefore, set the viewport width to 980 pixels, render the page at that width, and show the result as a zoomed-out version of the desktop layout. Other mobile browsers (e.g. on Google Android) did the same thing. Users could zoom in and pan around the website to view the bits they were interested in, but it looked bad. You will still see this today if you have the misfortune to come across a site that does not have a responsive design.

So you should always include the above line of HTML in the head of your documents.

  • initial-scale: Sets the initial zoom of the page, which we set to 1.
  • height:Sets a specific height for the viewport.
  • minimum-scale: Sets the minimum zoom level.
  • maximum-scale:Sets the maximum zoom level.
  • user-scalable:Prevents zooming if set to no.