Client Dashboard →
Q4 capacity now open. Roadmap in 5 business days.
Book strategy call
Web Design

How to Create a Responsive Website with HTML, CSS, and Media Queries

July 6, 2026 · 9 min read · By omorsarif
How to Create a Responsive Website with HTML, CSS, and Media Queries

How to Create a Responsive Website with HTML, CSS, and Media Queries

Building a responsive website from scratch requires a specific sequence of decisions and techniques. Get the foundation right and the rest of the process is straightforward. Skip steps or use shortcuts and you end up with a layout that looks fine on your laptop but breaks on a phone.

This guide walks through the full process: viewport configuration, CSS reset, mobile-first base styles, media queries, Flexbox and Grid layout, fluid images, and responsive typography. Code examples are included throughout to show each technique in practice.

Step 1. Set the Viewport Meta Tag

The viewport meta tag is the first and most critical step. Without it, mobile browsers render the page at 980px wide and zoom out to fit the phone screen. Your media queries trigger at the wrong widths because the browser is not using the actual device width.

Add this to the <head> section of every HTML file:

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

This single line tells the browser to set the viewport width equal to the device’s actual screen width and start at 1:1 zoom. Everything else in responsive design depends on this being correct.

Step 2. Apply a CSS Reset or Normalize

Different browsers apply different default styles to HTML elements. A CSS reset (or normalize) removes those inconsistencies so your styles behave the same across Chrome, Safari, Firefox, and Edge.

A minimal reset covers the most common default-style problems:

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

img, video {
  max-width: 100%;
  height: auto;
  display: block;
}

The box-sizing: border-box rule makes width calculations include padding and border, which prevents elements from overflowing their containers unexpectedly. The img max-width: 100% rule is the foundational responsive image technique that prevents images from overflowing their parent containers on narrow screens.

Step 3. Write Mobile-First Base CSS

Start every layout rule with mobile in mind. Write your default CSS for the smallest screen. Do not add media queries yet. Your base styles should produce a clean, single-column layout that works on a 375px phone.

A basic mobile-first page structure in CSS:

body {
  font-family: sans-serif;
  font-size: 1rem;
  line-height: 1.6;
  color: #222;
}

.container {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 1.25rem;
}

.section {
  padding: 3rem 0;
}

h1 { font-size: 1.875rem; }
h2 { font-size: 1.5rem; }
h3 { font-size: 1.25rem; }

Notice: no column widths, no float, no fixed pixel widths on content. The layout is fully fluid and single-column by default. Desktop enhancements come later in media queries. This is the mobile-first principle in practice.

Step 4. Add Media Queries for Larger Screens

Media queries apply additional CSS rules when the viewport meets specific conditions. For mobile-first design, you use min-width queries: apply these styles when the viewport is at least X pixels wide.

A standard responsive breakpoint structure with three breakpoints:

/* Tablet: 768px and up */
@media (min-width: 768px) {
  h1 { font-size: 2.5rem; }
  h2 { font-size: 1.875rem; }
  .section { padding: 4rem 0; }
}

/* Desktop: 1024px and up */
@media (min-width: 1024px) {
  h1 { font-size: 3.5rem; }
  h2 { font-size: 2.25rem; }
  .section { padding: 5rem 0; }
}

Place media queries at the bottom of your CSS file, or co-locate them with the selectors they modify. Co-location makes maintenance easier: all rules for a component live together. Bottom-of-file organization keeps a clean overview of all breakpoints in one place. Both approaches work. Pick one and stay consistent across the project.

Step 5. Build Layouts with Flexbox

Flexbox handles one-dimensional layouts: rows and columns. It is the right tool for navigation bars, card rows, button groups, and any arrangement where elements line up along one axis.

A responsive card row using Flexbox that stacks on mobile and goes side-by-side on tablet:

.card-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

.card {
  flex: 1 1 100%; /* Full width on mobile */
  padding: 1.5rem;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
}

@media (min-width: 768px) {
  .card {
    flex: 1 1 calc(50% - 0.75rem); /* Two columns on tablet */
  }
}

@media (min-width: 1024px) {
  .card {
    flex: 1 1 calc(33.333% - 1rem); /* Three columns on desktop */
  }
}

The flex: 1 1 100% shorthand sets flex-grow: 1, flex-shrink: 1, and flex-basis: 100%. On mobile, each card takes the full width. At 768px, the calc() value adjusts flex-basis so two cards fit per row while accounting for the gap. At 1024px, three cards fit per row.

Step 6. Use CSS Grid for Two-Dimensional Layouts

CSS Grid handles two-dimensional layouts: rows and columns simultaneously. It is the right tool for full page layouts and sections where you need to align items in both dimensions.

The most powerful responsive Grid feature for simple implementations is auto-fill with minmax():

.grid-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
}

This single rule creates a self-responsive grid. The browser calculates how many 280px columns fit in the available width and fills them with your card elements. On a 375px phone, you get one column. On a 768px tablet, you get two. On a 1200px desktop, you get four. No breakpoints needed for this layout; the grid figures it out.

For a full-page layout with a sidebar, Grid is cleaner than Flexbox:

.page-layout {
  display: grid;
  grid-template-columns: 1fr; /* Single column on mobile */
}

@media (min-width: 1024px) {
  .page-layout {
    grid-template-columns: 1fr 320px; /* Main content + sidebar on desktop */
    gap: 2rem;
  }
}

Step 7. Handle Images Responsively

The base rule from Step 2 (max-width: 100% on img) prevents image overflow. For production-quality responsive images, add the srcset attribute to serve different image sizes at different viewport widths:

<img
  src="hero-800.jpg"
  srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1200.jpg 1200w"
  sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 800px"
  width="800"
  height="450"
  loading="lazy"
  alt="Description of image"
>

The srcset lists available image files and their widths. The sizes attribute tells the browser how wide the image will display at each viewport size. The browser picks the best srcset entry for the current viewport and screen density. Adding explicit width and height prevents layout shift (CLS) as the image loads. The loading=”lazy” attribute defers loading of off-screen images.

For the hero image specifically (the largest visible element on load), skip lazy loading and add a preload link in the head instead:

<link rel="preload" as="image" href="hero-800.jpg" fetchpriority="high">

This tells the browser to start loading the hero image as early as possible, which improves Largest Contentful Paint (LCP). This is one of the most direct performance gains available in responsive image handling.

Step 8. Build Responsive Navigation

Navigation is one of the most visible responsive design challenges. A horizontal nav bar with five or more links needs to collapse on mobile. The standard approach: hide the nav links on mobile, show a hamburger button, and toggle visibility with JavaScript.

/* Base: mobile nav hidden */
.nav-links {
  display: none;
  flex-direction: column;
  gap: 1rem;
  padding: 1rem 0;
}

.nav-links.is-open {
  display: flex;
}

.hamburger {
  display: block;
  cursor: pointer;
}

/* Desktop: show nav, hide hamburger */
@media (min-width: 1024px) {
  .nav-links {
    display: flex;
    flex-direction: row;
    gap: 2rem;
    padding: 0;
  }
  .hamburger {
    display: none;
  }
}

The JavaScript toggles the is-open class on the nav-links element when the hamburger button is tapped. A few lines of vanilla JavaScript handle this without a framework.

Critical mobile navigation requirements: tap targets at least 44px by 44px, adequate spacing between items so users do not accidentally tap the wrong link, and a close mechanism (either an X button or closing when tapping outside the menu).

Step 9. Add Responsive Typography

Font sizes set in pixels do not scale with the viewport. Using rem units ties font sizes to the browser’s base font size (typically 16px) and respects user accessibility preferences. Use clamp() for fluid type that scales between sizes without hard breakpoint jumps:

h1 {
  font-size: clamp(1.875rem, 4vw + 1rem, 3.5rem);
}

h2 {
  font-size: clamp(1.5rem, 2.5vw + 0.75rem, 2.25rem);
}

p {
  font-size: clamp(1rem, 1.5vw + 0.5rem, 1.125rem);
  line-height: 1.7;
  max-width: 65ch; /* Limit line length for readability */
}

The clamp() function takes three arguments: minimum size, preferred size (viewport-relative), and maximum size. The heading scales from 30px at narrow viewports to 56px at wide ones with smooth scaling in between. The max-width: 65ch on paragraphs limits lines to roughly 65 characters wide, which is within the optimal 50 to 75 character range for readability.

Step 10. Test Across the Full Range of Screen Sizes

Open browser DevTools (F12 in Chrome), click the device toolbar icon, and test your layout at these widths: 320px, 375px, 430px, 768px, 1024px, 1280px, and 1920px. Also check between your breakpoints, such as 600px and 900px, where the layout transitions between states.

Look for these specific problems at each width: horizontal scrollbar (means something overflows), text that runs outside its container, images that distort or overflow, buttons and links with tap targets smaller than 44px, and navigation that does not function correctly.

Test on a real phone. DevTools emulation is useful for quick checks but does not replicate real touch behavior, the effect of the mobile browser bar on viewport height, or Safari’s CSS handling. At minimum, test the final site on one iOS device and one Android device before considering it done.

Common Mistakes to Avoid

  • Forgetting the viewport meta tag. Without it, all responsive CSS fails on mobile. This is the single most common responsive setup error.
  • Using fixed pixel widths on containers. A width: 960px container overflows on a phone. Use max-width combined with width: 100% and side padding instead.
  • Hiding mobile elements with display: none without removing them from the DOM. Elements hidden with CSS still load. A hidden desktop hero video still downloads on mobile, wasting bandwidth.
  • Not adding explicit width and height to images. Without these attributes, the browser does not know how much space to reserve for an image before it loads. The content below the image jumps when the image renders, causing Cumulative Layout Shift.
  • Writing desktop-first CSS and relying on max-width media queries. This works but produces heavier CSS than mobile-first. Mobile devices download all the desktop CSS and then override it. Mobile-first keeps mobile CSS lean.
  • Testing only in browser DevTools. Real devices catch real-world problems. Safari on iOS has different CSS behavior from Chrome. Test on actual hardware.

Going Further: Container Queries

Traditional media queries respond to the viewport width. Container queries respond to the width of a component’s parent element. This matters when you reuse a component in multiple contexts: a card in a narrow sidebar needs different layout than the same card in a wide main content area.

Container queries use the @container rule:

.card-wrapper {
  container-type: inline-size;
}

.card {
  display: grid;
  grid-template-columns: 1fr;
}

@container (min-width: 400px) {
  .card {
    grid-template-columns: auto 1fr;
  }
}

Container queries are supported in all major browsers as of 2023 and are safe for production use. They represent the next stage of responsive component design beyond viewport-based media queries.

Responsive Design Is a Build Process, Not a Feature

The techniques above are not a checklist to complete at the end of a project. Responsive design runs through every decision from the first line of CSS to the final device test. A viewport meta tag, mobile-first CSS, fluid images, and breakpoints set for your content are all foundational. Skip any of them and the result is a site that technically passes a mobile-friendly check but fails real users on real devices.

If you need a responsive site built by a team that applies all of these techniques by default, Redefine Web builds custom WordPress sites mobile-first from day one. Every build includes the techniques covered here plus performance optimization and Core Web Vitals testing before launch. See our responsive web design services page for more detail, or review our comparison of responsive vs adaptive web design if you are still deciding on the right approach for your project.

Share this article
OS
Written by

omorsarif — Founder

Stop guessing. Start ranking.

Book your free 30-minute strategy call.

No spam, no sales rep. We use your email to schedule your call with a senior strategist. That is it.

A senior strategist, not a sales rep.
A plain breakdown of what is working and what is not.
Three fixes you can keep, whether you hire us or not.
Zero obligation. Keep the notes either way.