Layout

Viewport Meta Tag: Responsive and Fixed-Width Pages

By Aigars Silkalns Updated 6 min read

Viewport Meta Tag: Responsive and Fixed-Width Pages

The viewport meta tag tells a mobile browser how wide to make the page before it lays it out. For a responsive site the answer is almost always width=device-width, initial-scale=1. For a fixed-width page that you have not made responsive yet, the better answer is a specific pixel width that matches your design, and you should never block zoom.

This guide covers what each value does, how to handle both fixed-width and responsive pages, and the newer pieces that matter today: viewport-fit, interactive-widget, and the svh, lvh and dvh units.

What the viewport tag actually does

Mobile browsers keep two viewports. The layout viewport is the box your CSS lays out against. The visual viewport is the part of that page the user sees at the current zoom. Without a viewport tag, mobile browsers assume a layout viewport of about 980 CSS pixels and shrink the result to fit the screen. That is why an old desktop site looks tiny on a phone.

The tag is a comma-separated list of key=value pairs in the head:

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

Values you will actually use

Value What it does Use it when
width=device-width Layout viewport equals the screen width in CSS pixels Every responsive page
width=720 Layout viewport is 720 CSS pixels, scaled to fit the screen Fixed-width pages that are not responsive yet
initial-scale=1 Starts at 100 percent zoom relative to the viewport width Responsive pages (the browser often does this anyway)
viewport-fit=cover Lets the page draw under notches and rounded corners Edge-to-edge layouts, paired with env(safe-area-inset-*)
interactive-widget Controls how the on-screen keyboard changes the viewport Chat inputs, bottom-fixed forms
user-scalable=no, maximum-scale=1 Tries to block pinch zoom Never

MDN documents the full list, including height, minimum-scale and maximum-scale, but the ones above cover almost every real project.

Responsive pages: keep it short

If your CSS adapts with media queries, container queries or fluid layouts, use exactly the tag above. MDN notes that initial-scale is usually unnecessary, so width=device-width alone also works, but including initial-scale=1 is harmless and widely used. Pair it with sensible CSS and you are done:

img, video { max-width: 100%; height: auto; }
.container { width: min(100% - 2rem, 72rem); margin-inline: auto; }

For the layout side, see Responsive Column Layouts and Setting Breakpoints in Responsive Design.

Fixed-width pages: match the viewport to your design

This is the trick the original version of this article was about, and it still works. Suppose your page has a 720px container and no responsive CSS. With no viewport tag, the browser lays it out at 980px and you get empty space on both sides. Setting the width to match your container fixes that:

<meta name="viewport" content="width=720">

The design does not change. The browser simply scales the 720px layout to fill the screen, and the user can still pinch to zoom. The same works the other way: if your design is 1024px wide and touches the screen edges at 980px, width=1024 shrinks it slightly so it fits.

I tested the same 720px page in a mobile-emulated browser at 390px screen width with three different tags:

Three phone screenshots of a fixed 720px page: no viewport tag leaves side gaps at 980px, width=720 fills the screen, and device-width crops the content with horizontal overflow
No tag lays the page out at 980px and leaves margins. width=720 fits the design exactly. device-width on a non-responsive page lays out at 390px, so the 720px content overflows.

In that test the page reported a layout width of 980px with no tag, 720px with width=720, and a 390px viewport with device-width, which clipped the 720px content. The third phone looks larger than the other two because that is real 1:1 rendering at 390px: text is bigger since nothing is shrunk to fit.

On a wider screen such as a tablet, width=720 does not shrink anything. The browser scales the 720px layout up to fill the screen or, depending on the browser, enforces its own minimum layout width, so do not expect a pixel-exact result. The same page can later move to width=device-width without changing the markup once you add a media-query layer that adapts below 720px.

A common mistake is adding initial-scale=1 to a fixed-width page, for example width=720, initial-scale=1. That asks for 100 percent zoom at the device width, which undoes the fit and gives you the cropped, horizontally scrolling page again. On a fixed-width page, set only the width.

Treat this as a stopgap. A fixed width on a phone means small text, so the real fix is a responsive layout. If you are converting, start with the useful CSS tricks for responsive design.

Never disable zoom

The most common mistake is copying a tag like this:

<!-- Don't -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

On any page it stops people with low vision from enlarging text. MDN warns that user-scalable=no prevents people with low vision from reading your content, and WCAG 1.4.4 (Resize Text, level AA) requires that text can be resized up to 200 percent without losing content or functionality.

They do not work consistently either. MDN notes that browser settings can ignore these values and that iOS 10 and later ignores them by default. iOS Safari ignores them; elsewhere they can still lock zoom and fail WCAG 1.4.4. Leave them out.

Notches, safe areas and viewport-fit

On phones with display cutouts, browsers keep the page inside the safe area by default. If you want a hero image or navigation bar to extend to the screen edges, opt in with viewport-fit=cover and then pad your content with the safe-area environment variables:

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
.site-header {
  padding-inline: max(1rem, env(safe-area-inset-left));
  padding-bottom: env(safe-area-inset-bottom);
}

MDN says to use cover together with the safe-area insets so important content is not hidden behind a cutout.

Keyboards: interactive-widget

When the on-screen keyboard opens, the default behavior (resizes-visual) shrinks only the visual viewport, so a fixed bottom bar can slide under the keyboard. The interactive-widget key changes this:

  • resizes-visual: default. The visual viewport shrinks, the layout does not.
  • resizes-content: the layout viewport shrinks too, so position: fixed bars, 100% heights and dvh sizes move above the keyboard (vh does not change).
  • overlays-content: the keyboard covers the page and neither viewport changes.
<meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content">

Support is not universal. According to MDN’s compatibility data, interactive-widget works in Chrome for Android 108 and later, Firefox for Android 133 and later, and Samsung Internet 21 and later. Safari on iOS and desktop browsers do not support it. Where it is ignored, the keyboard keeps the default resizes-visual behaviour, so treat it as an enhancement. If you need the same result everywhere, listen to window.visualViewport resize events and position the bar yourself, or on Chrome for Android use the VirtualKeyboard API to take over keyboard handling.

Viewport units: svh, lvh and dvh

The old 100vh hero causes trouble on phones because browser toolbars expand and retract. Modern CSS gives three variants of each viewport unit:

Unit Based on Behavior
svh Small viewport, toolbars shown Always fully visible, may leave a gap when toolbars hide
lvh Large viewport, toolbars hidden Fills the screen, may be partly covered by toolbars
dvh Current viewport Tracks the toolbars as they move, so it is not stable while scrolling

Plain vh equals lvh. The sv*, lv* and dv* units have shipped in Safari 15.4, Firefox 101, and Chrome and Edge 108, so all three engines support them. A safe pattern is svh for the minimum height, which never hides content:

.hero {
  min-height: 100vh;   /* fallback */
  min-height: 100svh;  /* never hidden behind toolbars */
}

Use dvh for full-screen panels such as modals and app shells, where you want an exact fit, and avoid it on content that would visibly resize as the user scrolls. Older iOS behavior is covered in CSS Fix for iOS vh-unit Bug.

Checklist

  1. Add <meta name="viewport" content="width=device-width, initial-scale=1"> to every responsive page.
  2. On a fixed-width page, set width= to your container width until you can make it responsive.
  3. Never add user-scalable=no or maximum-scale=1.
  4. Use viewport-fit=cover only with env(safe-area-inset-*) padding.
  5. Prefer svh, dvh and lvh over vh for full-height sections on mobile.
  6. Check the page in device emulation and on a real phone.

Mobile navigation is the next thing that usually breaks, so read Mobile Navigation Design & Tutorial next.

22 comments from the archive
  1. “…if your design is not responsive, do not reset the initial-scale or disable scaling…”

    I do fully agree on not disabling the zoom. However, I recently came across a design (which involved fixed elements), where the iPad/iPhone got the initial scale wrong. I was able to fix it by setting different initial-scales for each device (with the help of some javascript). The devices can still zoom in and out perfectly.

    What’s wrong about that?

    1. It depends on the situation and result. Will need to see the site that you mentioned.

      1. I linked the page on my reply’s name. The setting is done in application.js in case you inspect it. The odd thing was, even if I threw out the (100% width) header & footer, so that only the fixed width (1064px) container was visible, the iOS devices were not scaling right – if I remember correctly the page was to wide.

        Anyway…a fun fact I found out with this project: the iOS devices refuse to load ( tag embedded) pictures that are larger than certain (pixel) sizes.

        Google for “Know iOS Resource Limits” and you’ll find a document on apple.com talking about this. I’m pretty sure though it’s outdated as it says “devices with 256MB RAM” and also the pixel-limit mentioned is not correct anymore.

        Note that this issue seems to apply for ALL devices – even the older ones, so it seems to be something that has changed with the iOS version. I tested it on all devices on xcode simulator + a real 1st gen Ipad + a real iPhone 4.

        Try reproduce if you like.
        Create a blank jpg file in photoshop.

        Embed it as an image tag into a html file (I used html5, not sure if that matters anyhow).

        3200 x 1638 <- loads (that'd be 5.241.600 pixel)
        3200 x 1639 <- does not load

        Knowing this can save a lot of headaches when creating a mobile friendly image gallery (which is actually not used on the page I linked, it uses galleria.io).

        Maybe you want to blog about it some day.

  2. I didn’t know that viewport tags can be useful on non-responsive design, thanks for the tip.

  3. Hi Nick, thanks for sharing. An out of topic question here, do you plan to upgrade Themify, so that it have responsive feature?

  4. hey when i first found out that i could manipulate browsers to find my site easier it wasn’t working for me at all, then i found out put tags for however i would look for the site instead of how other people would, well then they started workin, thanks for the phone tip, thats how i started my page anyway….

  5. this is what I was looking for as I’m in the phase of testing my website on mobile devices… i really didn’t like how it was displayed. It will look better now, thanks to this post.

  6. A very good thing to know. It helped in 1 of my project that I am working but not actually thinking to have a mobile website for it.

    Thank you for sharing the article.

  7. Hey i just found this website and i think it is great! I enjoy reading your blog posts very much. I will continue visiting this website as it has great content.

    Thanks!

  8. Great post. It’s always important that we design for both mobile and desktop. These small tricks will enhance your users experience greatly.

  9. I love the Themify site on the iPhone. Thanks for sharing this. Cheers!

  10. Very helpful tutorial on adding a viewport tag to specify the viewport width for non-responsive design. It seems to work in all Android versions.

  11. Ey, Nick, where U at? I’m impatiently waiting for Ur next articles to read. Greetz!

  12. I guess you learn something new everyday. I was not familiar with this meta tag. Not sure if this will come in handy anytime soon. Most website I work with are designed using media queries, for responsive design?

  13. Thanks for the tip. It is a great help for some issues with a current client. Problem solved. I think I will share this with my web design friends on Facebook.

  14. Well, 100% make sense! I make “common” mistake – some parts of site was responsible, while others – not yet (i.e. in the progress)… so set content=”width=1024″ saves me :)
    Thanks!

  15. Liquid-crystal-display televisions (LCD TV) are television sets that use LCD display technology to produce images. LCD televisions are thinner and lighter than cathode ray tube (CRTs) of similar display size, and are available in much larger sizes. When manufacturing costs fell, this combination of features made LCDs practical for television receivers..**:

    a look at all of the most recent content on our personal web portal

  16. As we know that meta tag is one of the vital part in any web designing and this post deeply define its all aspects.

  17. Hello !
    This is an impressive detailed post about meta tag. Meta tag is too much important for the best designing, indeed. I totally agree with the common mistake, which usually people use to do.
    so thanks for sharing this post.
    Market of cleaning supplies

  18. Meta tag is one of the vital part in any web designing. I fully agree, the common mistake, which mostly people use to do.

Comments are closed on this article.