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
- W3C — Understanding WCAG 2.2 SC 1.4.4: Resize Text — text resizable to 200% without loss of content or functionality, Level AA.
- WebKit — New Interaction Behaviors in iOS 10 — Safari ignores
user-scalable=nofrom iOS 10, and why. - Chromium —
third_party/blink/renderer/core/html/html_meta_element.cc—ParseViewportValueAsUserZoomandParseViewportValueAsZoom: howuser-scalableandmaximum-scalevalues are read. - CSS Viewport Module — viewport meta parsing — separators and case-insensitive matching of property names and values.
- Deque — axe-core rule meta-viewport —
user-scalable=noormaximum-scalebelow 2 reported as a critical 1.4.4 failure.
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.