🚀 New batches open: Advanced Excel • Power BI • SQL • AI for Analytics — Book a free demo
Home / HTML Tutorial / Day 10

Day 10 — Responsive design - one page, every screen

More than half your visitors are on a phone. A page that only works on your laptop is a page that mostly does not work.

It starts with one line of HTML

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

Without it a phone pretends to be a 980px desktop and shrinks the whole page to fit, so your text ends up microscopic. No amount of CSS fixes that. It goes in the head of every page you ever write.

Media queries

@media (min-width: 700px) {
  /* only applies at 700px and wider */
}

The preview panes below are narrow, which makes them a decent stand-in for a phone. Drag the corner of your browser window to see the switch happen on this page too.

<style>
  body { font-family:system-ui, sans-serif; }
  .box { background:#E8EEF8; padding:20px; }
  .box p { margin:0; font-weight:700; }

  @media (min-width: 600px) {
    .box { background:#FDF3DA; }
    .box p::after { content: " - wide layout"; }
  }
</style>

<div class="box"><p>Narrow layout</p></div>

The preview is under 600px wide, so you see the blue version. Widen your browser and this whole page reflows too - the tutorial is built the same way.

Mobile-first

Write the phone styles as your normal CSS, then add what changes on bigger screens. Doing it the other way round means every rule needs an override, and phones - the slower devices - end up doing the most work.

<style>
  *, *::before, *::after { box-sizing:border-box; }
  body { font-family:system-ui, sans-serif; margin:0; padding:14px; }

  /* phone first: everything stacks */
  .grid { display:grid; gap:12px; }
  .grid div { background:#E8EEF8; padding:16px; border-radius:8px; }

  /* tablet */
  @media (min-width: 560px) {
    .grid { grid-template-columns: 1fr 1fr; }
  }
  /* desktop */
  @media (min-width: 900px) {
    .grid { grid-template-columns: 1fr 1fr 1fr; }
  }
</style>

<div class="grid">
  <div>Excel</div><div>Power BI</div>
  <div>SQL</div><div>Python</div>
</div>
Pick breakpoints from your content, not from devices There is no point memorising the iPhone’s width - there are hundreds of screen sizes and new ones every year. Make the window narrower until your layout looks bad, and put a breakpoint there. Around 600px and 900px covers most sites.

Images that behave

img { max-width: 100%; height: auto; }

Two lines that stop every image from bursting out of its container. max-width: 100% means "never wider than the space available"; height: auto keeps the proportions right.

<style>
  img { max-width:100%; height:auto; display:block; }
  .frame { max-width:220px; border:2px solid #1D3B73; padding:6px; }
</style>

<div class="frame">
  <img src="https://dai-academy.com/assets/logo.png"
       alt="DAI Academy logo" width="800" height="250">
</div>

The image file is far wider than 220px, but it shrinks to fit instead of breaking out. The width and height attributes stay on the tag so the browser can reserve the right space while it loads.

Units that flex

UnitMeansGood for
pxFixed pixelsBorders, small fixed gaps
%Of the parentWidths
remMultiple of the root font sizeType and spacing - scales if the user enlarges text
emMultiple of this element’s font sizePadding that should track the text
vw / vhPercent of the windowFull-height heroes
chWidth of a "0"max-width: 70ch for a readable line length
<style>
  html { font-size:16px; }
  .a { font-size:1.5rem; }
  .b { max-width:34ch; background:#E8EEF8; padding:.75rem; }
  .c { font-size: clamp(16px, 4vw, 26px); }
</style>

<p class="a">1.5rem is 24px here</p>
<p class="b">This paragraph is capped at 34 characters wide, which forces
   a short line length whatever the screen size.</p>
<p class="c">clamp: at least 16px, ideally 4vw, never more than 26px</p>
clamp is the modern answer to fluid type clamp(min, ideal, max) in one line replaces two media queries. Resize your browser and watch that last paragraph grow, then stop growing at 26px.

A responsive table

Day 4 showed the wrapper. Here it is with the CSS that makes it work.

<style>
  .scroller { overflow-x:auto; -webkit-overflow-scrolling:touch; }
  table { border-collapse:collapse; min-width:520px; font-size:14px; }
  th, td { border:1px solid #D3DDEC; padding:8px 12px; text-align:left; }
  th { background:#E8EEF8; }
</style>

<div class="scroller">
  <table>
    <thead><tr>
      <th>Course</th><th>Duration</th><th>Fee</th>
      <th>Batch</th><th>Mode</th>
    </tr></thead>
    <tbody><tr>
      <td>Advanced Excel</td><td>6 weeks</td><td>12,000</td>
      <td>Weekday</td><td>Classroom</td>
    </tr></tbody>
  </table>
</div>

min-width on the table stops the columns from crushing; overflow-x: auto on the wrapper lets the table scroll instead of the page. The rule is: the page must never scroll sideways. Something inside it may.

Touch targets

44 by 44 pixels, minimum A link that is easy to click with a mouse can be impossible to tap accurately with a thumb. Apple and Google both recommend at least 44px in each direction for anything tappable. Give small links padding rather than shrinking the text.
<style>
  .tiny a { font-size:12px; }
  .good a {
    display:inline-block; padding:12px 16px; min-height:44px;
    line-height:20px; background:#E8EEF8; border-radius:8px;
    text-decoration:none; color:#0A1A3D;
  }
</style>

<p class="tiny"><a href="https://example.com">Hard to tap</a></p>
<p class="good"><a href="https://example.com">Easy to tap</a></p>

Try these yourself

  1. Build a three-column card grid that becomes two columns, then one, as the screen narrows.
  2. Set an image to max-width 100% and prove it cannot overflow its container.
  3. Use clamp to make a heading scale between 20px and 40px.
  4. Wrap a six-column table so it scrolls sideways without moving the page.
  5. Explain why mobile-first CSS produces less code than desktop-first.