Explain Codes LogoExplain Codes Logo

How to disable viewport zooming in Mobile Safari?

html
responsive-design
best-practices
viewport
Alex KataevbyAlex Kataev·Feb 17, 2025
TLDR

To restrain zoom in Mobile Safari, add this to your HTML head:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

It sets the zoom level at 1.0, blocking pinch-to-zoom actions.

Pitfall Avoidance

While the fast solution should cover most situations, some corner cases may cause zooming to persist. Here's how to navigate those tricky waters:

  • Quotes: Double-check your HTML attributes for standard double quotes.
  • Attribute Layout: Ensure foundational attributes in your meta tag content value are comma-separated.
  • HTML Integrity: Run your code through an HTML validator. It's a debugger's best friend!
  • Reading Manuals: Plunge into Apple's official guidelines periodically. They might drip new guidelines for viewport configurations.

iOS 10+? CSS to the rescue!

iOS 10 onwards Apple made a move towards accessibility and started ignoring the user-scalable=no attribute. But fret not. You can control zoom through the CSS property touch-action.

Implement touch-action:

/* Innocently restricts zooming while allowing scrolling - just minding its own business! */ element { touch-action: pan-x pan-y; }

Ground rule: Choose pan-x pan-y over touch-action: none; - it saves your scrolling functionality from bellyflopping!

JavaScript-based pinch-to-zoom prevention:

// Well behaved and says "Thank you" to `gesturestart` events before promptly preventing them! document.addEventListener('gesturestart', function(event) { event.preventDefault(); });

Ageing iOS versions? Handle them too!

For legacy iOS versions (those nostalgic iOS 9 and before), apply event.preventDefault() to the touchmove event.

/* Ah, the good ol' days of older iOS versions. Only if they'd not allow zoom on touchmove! */ document.addEventListener('touchmove', function(event) { if (event.scale !== 1) { event.preventDefault(); } }, { passive: false });