There are two types of zoom. The 'pinch zoom' you get on mobile browsers where content disappears off the edges of the screen. And the 'page zoom' you get on desktop browsers, like when you do Ctrl +. After 'page zoom' the page is re-flowed, so with, a responsive layout you still see the whole page width.
How can I allow users to 'page zoom' on mobile devices?
I am thinking there could be a Zoom + and Zoom - button on the header bar of my site. I want this because I have a web app that the majority of users like, both on desktop and mobile browsers. But some less capable users find the site small and fiddly on some of their mobile devices. The ability to pinch zoom (which I have not disabled) is a help, but it means constant zooming in and out to navigate.
I have tried solutions involving CSS transform: scale(...)
and HTML <meta name="viewport" ...>
and altering these from JavaScript. But these all seem to have a 'pinch zoom' effect, not the page zoom I am after. Also transform: scale(...) causes problems with js based/pixelbased interaction types such as draggable which I use.
I have also looked at altering CSS font sizes from JavaScript. But this only works for text, not the images, <div>
s etc..
Apologies for answering my own question, but after a lot of tinkering, I found a way that works for me and seems to work on most web sites, so I thought it was worth sharing:
function zoom(scale) {
document.body.style.transform = "scale(" + scale + ")";
document.body.style.transformOrigin = "top left";
document.body.style.width = (100 / scale) + "%";
document.body.style.height = (100 / scale) + "%";
};
zoom(1.25);
The trick is to scale up the body with a scale transform, but then reduce the height and width. Reducing the height and width causes it to re-flow and keep the transformed content on the screen.
I tested the above code by pasting it into the console of Chrome Firefox and IE on several popular websites. It seems to perfectly re-scale amazon.com and stackoverflow.com, but not gmail. My own web app needed the patches described below.
Fuller solution with patches for jQuery:
With the above solution (and after pinch zoom), issues occur when JavaScript tries to measure pixel positions and use them to position other elements. This is because functions like getBoundingClientRect()
returns coordinates multiplied by scale
. If you use jQuery .height()
, .width()
, offset()
etc. you get the same issue; all jQuery docs says, "dimensions may be incorrect when the page is zoomed by the user".
You can fix jQuery methods like .width()
so deliver values as they would be if were viewing it with scale = 1
.
Edit since jQuery 3.2.0: height(), width(), etc. have been fixed and do not require the patch shown below. But offset() still needs the patch and if you use $(window).height() or width() to find the size of the view-port you will need to divide by scale.
var zoom = (function () {
var scale = 1, recurLev = 0;
function alter(fn, adj) {
var original = $.fn[fn];
$.fn[fn] = function () {
var result;
recurLev += 1;
try {
result = original.apply(this, arguments);
} finally {
recurLev -= 1;
}
if (arguments.length === 0 && recurLev === 0) {
result = adj(result);
}
return result;
};
}
function scalePos(n) { return n / scale; }
/* Not needed since jQuery 3.2.0
alter("width", scalePos);
alter("height", scalePos);
alter("outerWidth", scalePos);
alter("outerHeight", scalePos);
alter("innerWidth", scalePos);
alter("innerHeight", scalePos);
*/
alter("offset", function (o) { o.top /= scale; o.left /= scale; return o; });
return function (s) {
scale = s;
document.body.style.transform = "scale(" + scale + ")";
document.body.style.transformOrigin = "top left";
document.body.style.width = (100 / scale) + "%";
document.body.style.height = (100 / scale) + "%";
};
}());
zoom(1.25);
The only other issue I found was in code (like dragging and drawing etc) that uses positions from events like mousedown
, touchstart
, mousemove
, touchmove
etc. I found you had to scale pageX
and pageY
by dividing them by scale
.
If you are okay with replicating a "pinch zoom", then you can use the widely supported document.body.style.zoom
property.
Try running this in your console:
document.body.style.zoom = 2;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With