HTML & CSS — How to Make Web Pages Responsive?

Sherry Li
13 min readJan 3, 2023

--

Today’s users will use multiple devices to visit the same web page, so making your web page fit in different screen sizes is important to keep in mind. In this article, we will go through how to make web pages responsive.

🇨🇳 To read this article in Chinese, please visit my Zhihu. 文章的中文版请戳我的知乎

1. Media Queries @media

🔍 1.1 Media Types

A media type tells the browser what kind of media this code is for (e.g. print, or screen). Media types could be:

  1. all: Default value. Suitable for all devices.
  2. print: Intended for paged material and documents viewed on a screen in print preview mode.
  3. screen: Used for computer screens, tablets, smartphones, etc.
  4. speech: Used for screenreaders that “read” the page out loud.

🔍 1.2 Media Feature Rules

  1. Width & height: To create layouts that respond to different screen sizes, we could use width (width, min-width, max-width), height (height, min-height, max-height), and aspect ratio (aspect-ratio, min-aspect-ratio, max-aspect-ratio). Once the screen size meets the width and height rules, the CSS styles defined inside will be applied.
  2. orientation: The orientation property can be used to test the orientation of the viewport, so the value could be portait (height ≥ width) or landscape (width ≥ height).
  3. Resolution (resolution, min-resolution, max-resolution): This feature can be used to test the pixel density of the output device. The unit of pixel density is dpi (dots per inch), and to find your device’s pixel density, you could use DPI I love or DPI Checker.
  4. Use of pointing devices: The hover media feature can be used to test the user’s primary input mechanism can hover over elements, while the any-hover media feature can be used to test whether any available input mechanism can hover over elements, the value could be none (the input mechanism cannot conveniently hover, or there is no pointing input mechanism), or hover(the input mechanism can conveniently hover over elements). The 2 attributes are suitable to be used when PC and mobiles display the same button, and we require a hover effect on the PC. The pointer media feature tests whether the user’s primary input mechanism includes a pointing device and how accurate it is, while the any-pointer media feature tests whether the user has any pointing device and how accurate it is, the value could be none (no pointing device), coarse (the pointing device has limited accuracy), or fine (the pointing device is accurate). The 2 attributes are suitable to be used to improve user experience with a pointing device with limited accuracy (such as increasing the size of a checkbox).
  5. prefers-color-scheme: The prefers-color-scheme media feature is sued to detect if the user has requested a light or dark theme, the value could be light (the user prefers an interface that has a light theme, or has not expressed an active preference), or dark (the user prefers an interface that has a dark theme).

🔍 1.3 Logical Operators

To combine different media queries or create lists of media queries, we will use some logical operators.

  1. and: Combine multiple media features together into a single media query, requiring each chained feature to be true.
  2. not: Used to negate a media query, returning true if the query returns false. ⚠️ If you use the not operator, you must also specify a media type.
  3. only: Applies a style only if an entire query matches. ⚠️ If you use the only operator, you must also specify a media type.
  4. , (comma): Combine multiple media queries into a single rule, if any of the queries in the comma-separated list is true, the entire media statement returns true. It is like an “or” logical operator.

1.4 Media Queries

Now, let’s see how to create CSS media queries.

/* Screen width >= 600px */
@media screen and (min-width: 600px) {
div {
background: lightblue;
}
}

/* Only when print preview mode */
@media only print {
h1 {
font-size: 30px;
}
}

💻 For more example code about the media queries, you could visit my CodePen.

If you want to view what media queries your current device satisfies, you could check CSS3 Media Queries.

📃 References

📌 https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Media_queries

📌 https://www.w3schools.com/css/css3_mediaqueries.asp

📌 https://zhuanlan.zhihu.com/p/168791704

2. The Viewport <meta> Tag

The viewport is the user’s visible area of a web page. HTML introduces the <meta> tag with name="viewport" to take control over the viewport’s size and shape.

The most common viewport <meta> tag we include in code is:

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

The above code tells the browser to set the width of the page to follow the screen width of the device (by width=device-width), and to set the initial zoom level when the page is first loaded to 1 (by initial-scale=1.0).

The most common properties we define in the content attribute are:

  1. width: The width property sets a specific width for the viewport. The value could be a specific number (between 1 and 10000) or device-width .
  2. height: The height property sets a specific height for the viewport. The value could be a specific number (between 1 and 10000) or device-height.
  3. initial-scale: The initial-scale property sets the initial zoom level of the page when the page is first loaded. The value could be a specific number between 0.1 and 10.
  4. minimum-scale: The minimum-scale property sets the minimum allowed zoom level of the page. The value could be a specific number between 0.1 and 10.
  5. maximum-scale: The maximum-scale property sets the maximum allowed zoom level of the page. The value could be a specific number between 0.1 and 10.
  6. user-scalable: The user-scalable property controls whether zoom in and zoom out actions are allowed on the page. The value could be yes (allow zoom in and zoom out actions) or no (disallow zoom in and zoom out actions).

To view your current device’s viewport, you could check What is my viewport.

You could visit MDN — Viewport meta tag and W3Schools — Responsive Web Design — The Viewport to get a more complete understanding of the viewport <meta> tag.

3. Responsive Layout Technologies

💡 3.1 Flexbox (Flexible Box) Layout

The main idea behind the flex layout is to give the container the ability to alter its items’ width/height (and order) to best fill the available space (mostly to accommodate to all kind of display devices and screen sizes). A flex container expands items to fill available free space or shrinks them to prevent overflow.

To define a flexbox, we will:

  1. Define the container as display: flex; .
  2. Define the styles of the flex container and the flex items.

The following are some common properties we use to style flex containers:

  1. flex-direction: The flex-direction property establishes the main-axis, thus defining the direction flex items are placed in the flex container. The value could be row (left to right in ltr; right to left in rtl ), row-reverse, column (top to bottom in ltr; bottom to top in rtl), or column-reverse .
  2. flex-wrap: The flex-wrap property allows the items to wrap as needed with this property. The value could be no-wrap (all flex items will be on one line), wrap (flex items will wrap onto multiple lines, from top to bottom), or wrap-reverse .
  3. justify-content: The justify-content property defines the alignment of flex items along the main axis. The value could be flex-start (items are packed toward the start of the flex-direction), flex-end, center, space-between (items are evenly distributed in the line; first item is on the start line, last item on the end line), space-around (items are evenly distributed in the line with equal space around them; the first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies), or space-evenly (items are distributed so that the spacing between any two items and the space to the edges is equal).
  4. align-items: The align-items property defines the default behavior for how flex items are laid out along the cross axis on the current line. The value could be flex-start, flex-end, center, stretch, or baseline.

The following are some common properties we use to style flex items:

  1. flex-basis: The flex-basis property sets the initial main size of a flex item.
  2. flex-grow : The flex-grow property sets the flex grow factor of a flex item's main size.
  3. flex-shrink: The flex-shrink property sets the flex shrink factor of a flex item.
<div class="flex-container">
<div class="flex-item">1</div>
<div class="flex-item">2</div>
<div class="flex-item">3</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
<div class="flex-item">6</div>
</div>
.flex-container {
width: 200px;
border: 1px solid blue;
display: flex;
flex-wrap: wrap;
justify-content: center;
}

.flex-item {
width: 50px;
height: 50px;
background: pink;
margin: 10px;
}

💻 For more example code about the flexbox layout, you could visit my CodePen — flex and CodePen — flex-flow.

You could visit MDN — CSS Flexible Box Layout and CSS-TRICKS — A Complete Guide to Flexbox to get a more complete understanding of the flexbox layout.

💡 3.2 Grid Layout

A grid is a collection of horizontal and vertical lines creating a pattern against which we can line up our design elements. They help us to create layouts in which our elements won’t jump around or change width as we move from page to page, providing greater consistency on our websites.

A grid will typically have columns, rows, and then gaps between each row and column. The gaps are commonly referred to as gutters.

To define a grid, we will:

  1. Define the container as display: grid; .
  2. Define the styles of the grid container and the grid items.

The following are some common properties we use to style grid containers:

  1. grid-template: The grid-template property is a shorthand property for the grid-template-rows (defines the grid rows), grid-template-columns (defines the grid columns) and grid-template-areas (defines the grid areas) properties.
  2. gap: The gap property is a shorthand property for the row-gap (sets the size of the gap between elements’ rows) and column-gap (sets the size of the gap between elements’ columns) properties.
  3. justify-items: The justify-tiems property aligns items along the row axis. The value could be start(aligns items to be flush with the start edge of their cell), end(aligns items to be flush with the end edge of their cell), center(aligns items in the center of their cell), or stretch(default value, fills the whole width of the cell).
  4. align-items: The align-items property aligns items along the column axis. The value could be start, end, center, stretch, or baseline.

The following are some common properties we use to style grid items:

  1. grid-column: The grid-column property is a shorthand property for the grid-column-start and grid-column-end properties, which determines the grid item’s location with value <start-line> / <end-line>.
  2. grid-row: The grid-row property is a shorthand property for the grid-row-start and grid-row-end properties, which determines the grid item’s location with value <start-line> / <end-line> .
  3. grid-area: The grid-area property gives a grid item a name so that it can be referenced by a template created with the grid-template-area property.
<div class="grid-container">
<div class="grid-item1">1</div>
<div class="grid-item2">2</div>
<div class="grid-item3">3</div>
</div>
.grid-container {
display: grid;
border: 1px solid red;
padding: 10px;
grid-template:
"a a ." 50px
"a a ." 1fr
". b c" 70px
". b ." 20px / 150px 1fr 50px;
/*
grid-template-rows: 50px 1fr 70px 20px;
grid-template-columns: 150px 1fr 50px;
grid-template-areas:
"a a ."
"a a ."
". b c"
". b .";
*/
}

.grid-item1 {
grid-area: a;
background: lightblue;
}

.grid-item2 {
grid-area: b;
background: orange;
}

.grid-item3 {
grid-area: c;
background: lightgreen;
}

💻 For more example code about the grid layout, you could visit my CodePen — grid-template, CodePen — grid-area, grid-column, grid-row, and CodePen — grid.

You could visit MDN — Grids and CSS-TRICKS — A Complete Guide to CSS Grid to get a more complete understanding of the grid layout.

💡 3.3 Multiple-Column Layout

To define multiple columns and style those columns, we will use the following properties:

  1. columns: The columns property is a shorthand property for the column-count (breaks the element’s content into a specific number of columns) and column-width(defines the ideal width of each column) properties.
  2. column-gap: The column-gap property sets the size of the gap between columns.
  3. column-rule: The column-rule property is a shorthand property for the column-rule-width(sets the width of the line drawn between columns), column-rule-style(sets the style of the line drawn between columns), and column-rule-color (sets the color of the line drawn between columns) properties.
.article {
columns: 3;
/* column-count: 3; */
column-rule: 3px dotted blue;
/*
column-rule-width: 3px;
column-rule-style: dotted;
column-rule-color: blue;
*/
column-gap: 20px;
}

💻 For more example code about the multiple-column layout, you could visit my CodePen.

You could visit MDN — Multiple-column layout to get a more complete understanding of the multiple-column layout.

4. Responsive Typography

The most common length unit we use is px , which is an accurate absolute length unit in browser. Responsive typography introduces using relative length units such that the font sizes could respond to different font sizes or viewports.

The following are the most common relative length units we use:

  1. em: Font size of the parent, in the case of typographical properties like font-size ; and font size of the element itself, in the case of other properties like width.
  2. rem: Font size of the root element.
  3. vw: 1% of the viewport’s width.
  4. vh: 1% of the viewport’s height.

💻 For some example code about relative length units, you could visit my CodePen.

To convert px to rem, here are some useful tools:

  1. PX to REM converter
  2. px to rem (Visual Studio Code Extension)
  3. px to rem & rpx & vw (cssrem) (Visual Studio Code Extension)

5. Responsive Images

In order to make images fit well on different screens/devices, it is good to leverage the concepts of responsive images.

💡 5.1 Use the HTML srcset Attribute or the CSS image-set() Function

<img> tag provides an attribute srcset to help load different image sources for devices with different resolutions.

The value of the srcset attribute is one or more strings separated by commas, each string is composed of:

  1. A URL to an image.
  2. Optionally, whitespace followed by one of:

2a) A width descriptor (a positive integer directly followed by w). The width descriptor is divided by the source size given in the sizes attribute to calculate the effective pixel density.

2b) A pixel density descriptor (a positive floating point number directly followed by x). You could use window.devicePixelRatio in JavaScript to see your device’s pixel density.

<img
src="https://www.shareicon.net/data/512x512/2016/06/01/576694_background_600x600.png"
srcset="https://www.shareicon.net/data/64x64/2016/06/01/576694_background_600x600.png,
https://www.shareicon.net/data/256x256/2016/06/01/576694_background_600x600.png 1.5x,
https://www.shareicon.net/data/512x512/2016/06/01/576694_background_600x600.png 2x"
alt="Blue Background"
/>

The image-set() CSS functional notation is a method of letting the browser pick the most appropriate CSS image from a given set, primarily for high pixel density screens.

.image {
width: 100px;
height: 100px;
background-image: image-set(
url("https://www.shareicon.net/data/64x64/2016/06/01/576694_background_600x600.png") 1x,
url("https://www.shareicon.net/data/256x256/2016/06/01/576694_background_600x600.png") 1.5x,
url("https://www.shareicon.net/data/512x512/2016/06/01/576694_background_600x600.png") 2x);
}

💡 5.2 Use the HTML srcset and sizes Attributes

Combining the sizes attribute to the srcset attribute, we can define which image with which size will best fit on different screens.

The value of the sizes attribute is one or more strings separated by commas, each source size consists of:

  1. A media condition. This must be omitted for the last item in the list.
  2. A source width value.
<img 
src="https://www.shareicon.net/data/512x512/2016/06/01/576694_background_600x600.png"
srcset="https://www.shareicon.net/data/64x64/2016/06/01/576694_background_600x600.png 100w,
https://www.shareicon.net/data/256x256/2016/06/01/576694_background_600x600.png 200w"
sizes="(max-width: 600px) 100px,
200px"
alt="Blue Background"
/>

💡 5.3 Use Aspect Ratio to Resize and Crop Images by the CSS padding and background Properties

It is common to have a requirement that asks you to resize and crop images according to some specific aspect ratio. One way to meet such a requirement is to use the CSS padding and background properties.

<div class="image-continer">
<!-- 1:1 -->
<div id="one-to-one"/>
</div>
.image-container {
width: 200px;
}

Resize the image with aspect ratio: Since the percentage value of the padding property is relative to the width of the containing block, first we set the value of the width property and set the height to 0, then we can set the padding property to any percentage value such that we can resize the image to any aspect ratio correspondingly.

Crop the image: As we use the <div> tag for displaying images, we put the image source inside the background property, and which part of the image we want to display can be defined using the background-size and background-position properties.

💡 5.4 Use Aspect Ratio to Resize and Crop Images by the CSS aspect-ratio and object-fit Properties

Another way to base aspect ratio to resize and crop images is using the CSS aspect-ratio and object-fit properties. The aspect-ratio property allows us to resize an image with any ratio, and the object-fit property allows us to set how an image could be resized.

<!-- 16:9 -->
<img
id="sixteen-to-nine"
src="https://images.unsplash.com/photo-1554629947-334ff61d85dc?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=256&h=256&q=80"
/>
/* 16:9 */
#sixteen-to-nine {
width: 200px;
aspect-ratio: 16 / 9;
object-fit: cover;
}

You could visit MDN — aspect-ratio and MDN — object-fit to get a more complete understanding of these 2 properties.

📃 References

📌 https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images

📌 https://css-tricks.com/a-guide-to-the-responsive-images-syntax-in-html/

📌 https://www.smashingmagazine.com/2014/05/responsive-images-done-right-guide-picture-srcset/

📌 https://blog.51cto.com/u_15127633/2742418

6. Responsive Frameworks

There are also responsive frameworks you could import into your project.

  1. Bootstrap
  2. Foundation
  3. Skeleton
  4. UIkit
  5. Bulma
  6. Semantic UI
  7. Materialize
  8. MUI (Material UI)

--

--