deadhead
meta/viewport-user-scalable

meta viewport that disables zoom

A viewport with user-scalable=no or a maximum-scale below 2 stops people zooming to read, failing WCAG 1.4.4.

  • Avoid
  • Harmful
Severity
HarmfulActively breaks something for users.
Basis
SpecifiedThe evidence is in a current standard.
Detectable
YesMatched exactly. Autofixable when the rule carries a fix.
Matches
meta[name="viewport" i][content*="user-scalable" i], meta[name="viewport" i][content*="maximum-scale" i] + logic moduleElement rule, inside <head>.
Fix
None — reports only
Impacts
Accessibility
Related
head/viewport

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> is copied into templates to make a site feel like an app: no accidental zoom on double-tap, no input zoom on focus, a layout that never shifts. It does that by taking pinch-zoom away from everyone, including the people who can’t read the page without it.

Why avoid

It fails a Level AA success criterion. WCAG 2.2 SC 1.4.4 Resize Text requires that text “can be resized without assistive technology up to 200 percent without loss of content or functionality”. On a phone, pinch-zoom is that mechanism. user-scalable=no switches it off, and a maximum-scale below 2 caps it short of 200%. Deque’s axe-core reports exactly this pattern as a critical violation of 1.4.4, and the threshold of 2 is the 200% in the criterion.

It works where most people browse. Chromium’s viewport parser maps user-scalable=no, and also 0, false, an empty value or any number between -1 and 1, to “no user zoom”, and it clamps zoom to maximum-scale. Chrome on Android and every Chromium-based browser therefore lock the page at that scale, unless the user has found and enabled a force-zoom accessibility setting.

Apple already decided it was harmful. From iOS 10, Safari ignores user-scalable=no and lets users pinch-zoom every page. WebKit’s explanation is the whole case against the tag: it “enabled pages to pick a text size that was unreadable while giving the user no way to zoom”. So the value is harmful where it is honoured and ignored where it isn’t, and in neither place does it deliver the app-like feel it was added for.

Use instead

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

Fix the specific annoyance instead of the whole page. iOS zooms into a focused input whose text is smaller than 16px, so set font-size: 1rem or larger on form controls. If double-tap zoom gets in the way of a control, touch-action: manipulation on that control removes the double-tap delay without disabling pinch-zoom.

Detectability

Fully detectable from the attribute. The selector narrows to viewports whose content mentions user-scalable or maximum-scale, and the logic parses content the way browsers do. Pairs are separated by commas, semicolons or whitespace, with whitespace allowed around =. Keys are case-insensitive, and a later pair overrides an earlier one. It reports when user-scalable is anything other than yes, device-width, device-height or a number of magnitude 1 or more, or when maximum-scale is yes, no, or a number from 0 up to but not including 2. A negative maximum-scale means auto and isn’t reported, and neither is an unrecognised word there.

Chromium treats a semicolon as an invalid separator, so a semicolon-separated user-scalable=no may not take effect in Chrome. It is still reported. The markup states the intent, and other engines have accepted semicolons.

There is no autofix. The problem is one pair inside content, which no fix op can edit, and deleting the element would throw away the width=device-width the layout depends on.

Resources

This page is generated from content/rules/meta/viewport-user-scalable.md, the same file the linter is built from. Think the rule is wrong, or that browsers moved on? Say so — that is the most useful issue you can file.