Skip to main content
Syllabus
On this page

Mobile-First & the Viewport

Badar KhalilUpdated September 30, 2026 9 min read

Mobile-First CSS and the Viewport: Complete Guide

Focus keyword: mobile-first CSS. Most web traffic today comes from phones. Mobile-first means you write the styles for the smallest screen first, then add complexity for larger screens with min-width media queries. Together with the viewport meta tag, it is the foundation of every responsive website. In this lesson you will learn how the viewport works, why mobile-first produces simpler CSS, how to use modern viewport units, how to handle notches with safe-area insets, how to size touch targets, and how to avoid the most common responsive bugs.

mobile-first design, viewport meta tag, width=device-width initial-scale=1, layout viewport vs visual viewport, min-width media queries, mobile-first vs desktop-first, svh lvh dvh units, 100vw horizontal scroll, safe-area-inset env(), viewport-fit cover, touch target size, WCAG 2.2 target size, pointer coarse, hover hover, progressive enhancement, device pixel ratio, responsive web design basics, mobile SEO, Core Web Vitals on mobile.

1. What Is Mobile-First?

Mobile-first is a way of writing CSS and of planning content. You start with a single column layout that works on a small phone, then you use @media (min-width: ...) to enhance the layout when more space is available. The base CSS is the mobile design, and media queries only add. This is the opposite of desktop-first, where you design a complex layout and then remove or undo things with max-width queries.

  • Simpler CSS: small screens get the least CSS and the simplest layout, which is usually faster on slow phones and networks.
  • Fewer overrides: you add rules instead of undoing rules.
  • Content priority: it forces you to decide what is really important.
  • Progressive enhancement: every browser gets a working baseline, and capable browsers get more.
  • SEO: search engines index the mobile version of a page first.

2. The Viewport Meta Tag

Without a viewport tag, a mobile browser pretends the screen is about 980px wide and then shrinks the page, so your media queries never match the real screen width. Always add this tag inside the head: <meta name='viewport' content='width=device-width, initial-scale=1'>.

  • width=device-width: the layout viewport equals the screen width in CSS pixels.
  • initial-scale=1: no initial zoom.
  • viewport-fit=cover: lets the page draw under notches and rounded corners. Combine it with safe-area insets.
  • interactive-widget=resizes-content: changes how the on-screen keyboard affects the layout in supporting browsers.
  • Never add user-scalable=no or maximum-scale=1. They block pinch zoom and fail accessibility rules, because people with low vision need to zoom.

3. Layout Viewport, Visual Viewport and CSS Pixels

The layout viewport is the area your CSS layout uses. The visual viewport is the part the user currently sees, and it changes when the user pinch-zooms or when the keyboard opens. A CSS pixel is not a physical pixel. A high density phone may have a device pixel ratio of 3, which means one CSS pixel is drawn with 3 by 3 device pixels. That is why a phone with a 1170 physical pixel width reports about 390 CSS pixels, and why you should serve sharper images to high density screens.

4. Mobile-First Media Queries

Write the base styles with no query, then use min-width:

  • Base: single column, full width.
  • @media (min-width: 600px): two columns.
  • @media (min-width: 960px): three columns, sidebar, larger spacing.

Choose breakpoints where your content starts to look bad, not only at device sizes. Use em or px consistently. You will study media queries in detail in the next lesson.

5. Viewport Units: vh, svh, lvh and dvh

On phones the address bar and toolbars appear and disappear, so 100vh can be taller than the visible area and push content out of sight. Modern units solve it:

  • svh: small viewport height, the visible height when browser bars are shown. Safe for content that must always be visible.
  • lvh: large viewport height, when bars are hidden.
  • dvh: dynamic viewport height, updates while bars move. Great for full screen sections, but it can cause layout changes while scrolling.
  • The same family exists for width and for logical directions: svw, lvw, dvw, svi, dvb.

A common pattern is min-height: 100svh for a hero and min-height: 100dvh for an app shell.

6. The 100vw Trap

width: 100vw includes the vertical scrollbar width on desktop, so the element becomes wider than the visible area and creates horizontal scrolling. Prefer width: 100% on block elements. A block element is already full width by default, so you often do not need a width at all. Also avoid fixed pixel widths larger than small phones, and use max-width: 100% for images and media.

7. Safe Area Insets for Notches

When you use viewport-fit=cover, use env(safe-area-inset-top), env(safe-area-inset-right), env(safe-area-inset-bottom) and env(safe-area-inset-left) to keep buttons and bars away from notches and gesture bars. Always give a fallback, for example env(safe-area-inset-bottom, 0px). Combine with max(): padding-bottom: max(1rem, env(safe-area-inset-bottom)).

8. Touch Targets

Fingers are less precise than a mouse. WCAG 2.2 requires at least 24 by 24 CSS pixels for a target (level AA) and recommends 44 by 44 pixels (level AAA). Many platform guidelines use 44 to 48 pixels. Add padding instead of only making text bigger, and keep space between targets so users do not tap the wrong one.

9. Input Capabilities: pointer and hover

Screen width does not tell you how the user interacts. A tablet can be wide and touch only, and a small laptop window can have a mouse. Use @media (pointer: coarse) for touch and @media (hover: hover) for devices that can really hover. Wrap hover-only effects inside (hover: hover) so touch devices do not get sticky hover states. Use any-pointer and any-hover when the device has more than one input.

10. Mobile-First Workflow

  1. Write semantic HTML and read it without CSS. The reading order should make sense on a phone.
  2. Add the viewport meta tag, a box-sizing reset and base typography.
  3. Style the single column mobile layout.
  4. Resize the browser wider. When the layout looks stretched or empty, add a breakpoint.
  5. Enhance with grid, flexbox and larger spacing inside min-width queries.
  6. Test in DevTools device mode, then on real phones, with zoom and with keyboard.

11. Performance on Mobile

  • Ship less CSS and JavaScript to small screens. Do not hide large desktop-only images with display none, because they may still download. Use responsive images.
  • Use system fonts or a small number of web fonts with font-display: swap.
  • Lazy load images below the fold.
  • Keep the layout stable to protect the Cumulative Layout Shift score.

12. Common Mistakes

  • Forgetting the viewport meta tag.
  • Blocking zoom with user-scalable=no.
  • Writing desktop-first CSS and then fighting max-width overrides.
  • Using 100vw and creating a horizontal scrollbar.
  • Using 100vh for full screen sections on phones and cutting off content.
  • Tiny tap targets placed close together.
  • Hover-only menus and tooltips that cannot be used on touch screens.
  • Testing only in a resized desktop window and never on a real device.

Key Takeaways

Add the viewport meta tag, write the small screen layout as your base, enhance with min-width queries, use svh, lvh and dvh instead of a risky 100vh, protect notches with safe-area insets, make touch targets large, and detect input with pointer and hover rather than guessing from width.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself HTML
Output

Press Run to execute.

Try it Yourself JAVASCRIPT
Output

Press Run to execute.

Exercise: Convert a Desktop-First Layout to Mobile-FirstHTML

The CSS below starts with the desktop layout and undoes it with max-width. Rewrite it mobile-first: the base styles must be a stacked single column, and a min-width: 700px query must create the row with a 240px sidebar.

Try it Yourself HTML
Output

Press Run to execute.

Show expected output
Base styles are stacked with no max-width query, and @media (min-width: 700px) adds display: flex and the 240px sidebar

This is a self-check — compare your result with the expected output above.

Exercise: Fix the Horizontal Scroll and the ViewportHTML

Add the correct viewport meta tag and remove the horizontal scrollbar caused by width: 100vw. Also replace the fixed 900px width with a flexible width that never exceeds 900px, and do not block user zoom.

Try it Yourself HTML
Output

Press Run to execute.

Show expected output
A meta viewport tag with width=device-width, initial-scale=1 and no user-scalable=no, the hero without 100vw, and .content using width: min(100%, 900px) or max-width: 900px

This is a self-check — compare your result with the expected output above.

Was this page helpful?