Make Android's Pinch Zoom-Feature more Accessible
Since I'm getting older I often need to pinch zoom into web pages to make the text more readable.
However, Android (or Chrome) has the annoying "feature" to enlarge the whole viewport when zooming into a web page, forcing the user to scroll horizontally through the page to read the text:
Currently it seems that there is no way to disable this behaviour from the developer's side using CSS or HTML. Although Chrome as a so-called reading mode I see this only as a workaround, since the user must know about this mode and must enable it manually for each single website – and does not work on all pages.
So I experimented a bit and found a JavaScript-based solution that is pretty simple. You need some sort of container for that you want to re-flow the text on pinch zoom (in this example the HTML element main
), and it should have no margins when in mobile view. I also suggest to add overflow-wrap: break-word;
to your CSS, since otherwise long URLs might break the layout.
Then insert the following JavaScript code at the end of your HTML file:
<script>
// Force Android's browsers to reflow content on pinch zoom
if (navigator.userAgent.match(/android/i) && window.visualViewport && window.visualViewport.scale) {
let scaleTimeoutId = undefined
window.visualViewport.addEventListener("resize", (() => {
if (scaleTimeoutId != undefined) {
window.clearTimeout(scaleTimeoutId)
}
// Apply changes if the value has not changed for more than 250ms to prevent flickering
scaleTimeoutId = window.setTimeout(() => {
scaleTimeoutId = undefined
var scaleFactor = window.visualViewport.scale
var main = document.getElementsByTagName('main')[0]
if (scaleFactor > 1) {
main.style.maxWidth = "" + Math.round(100/scaleFactor) + "%"
// Add a CSS class that allows to do modifications on default styles,
// like removing 'margin: auto'.
main.classList.add('pinchzoom')
} else {
main.style.maxWidth = ''
main.classList.remove('pinchzoom')
}
}, 250)
}))
}
</script>
This uses the VisualViewport's scale
property to set the maximum width of the container element to the scale factor's inverse value and thus force the browser to wrap the text along the actual viewport's size:
An issue of this method is that since the text gets rearranged it might flow out of the visual viewport. I've tried to workaround this problem by identifying the centered element of the visual viewport and scroll this into view after the 'max-width' style had been applied, but due to limitations on scrollIntoView() this is far from being perfect. See /js/reflow.js for the current full version if this code.
I don't know if this works on all Browsers, and if it does not have any other side effects, so I would be happy to get some feedback!