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..
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..
- Possibly duplicate of stackoverflow./questions/1156278/… – user6360214 Commented Oct 19, 2016 at 12:09
-
@SuperCoolHandsomeGelBoy I don't think it is a duplicate of 1156278, because
transform: scale(...)
is a 'pinch zoom'. Alsotransform: scale(...)
causes problems with js based/pixelbased interaction types such as draggable which I use. – James Commented Oct 19, 2016 at 12:21 - If you want to control zooms with javascript, this requires a lot of calculations and cannot be answered in a short time – user6360214 Commented Oct 19, 2016 at 12:22
- Related question about making pinch gestures, which usually perform zoom without reflow, instead perform what you call 'page zoom', i.e. zoom with reflow: stackoverflow./questions/17075003 – root Commented Dec 22, 2024 at 11:33
4 Answers
Reset to default 8Apologies 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. and stackoverflow., 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;
Hi you can try this
css:
div {
margin: 150px;
width: 200px;
height: 100px;
background-color: yellow;
border: 1px solid black;
border: 1px solid black;
-ms-transform: scale(2,3); /* IE 9 */
-webkit-transform: scale(2,3); /* Safari */
transform: scale(2,3); /* Standard syntax */
}
Html:
<div>
This div element is two times of its original width, and three times of its original height.
</div>
Change font size on everything? So basically, every font size you define would need to use em
as its units (intstead of px
for example) so that it bee a fraction of the default font.
Then you can set the body's font size (in px
) to change the size of all the fonts.
function zoomPage(amount) {
var currentSize = Number(window.getComputedStyle(document.body, null).getPropertyValue('font-size').match(/\d+/));
console.log(Number(currentSize), amount, (currentSize + amount));
document.body.style.fontSize = (currentSize + amount) + 'px';
}
body {
font-size: 20px;
font-family: sans-serif;
max-width: 300px;
}
#smaller {
font-size: 0.5em;
}
.noresize {
font-size: 20px;
}
<button class="noresize" onclick="zoomPage(1)">+</button><button class="noresize" onclick="zoomPage(-1)">-</button>
<h1>I am big text</h1>
<p>I am <i>smaller</i> text</p>
<p id="smaller">I am even smaller text, even though I am also a paragraph</p>