34

On an HTML website, you have a fixed element like this:

<div id="fixed">
  <p>Some content</p>
</div>

It has this CSS:

#fixed { height:150px; position:fixed; top:0; left:0; z-index:10000; }

When you view this page on a mobile device (or any touchscreen-enabled device), and you pinch the screen to zoom in, the fixed element zooms in along with all the other content (it gets bigger). When you zoom in far enough, it becomes so big that it almost fully overlaps all the content beneath it.

A practical use case would be a UI like a fixed navigation bar across the top, or a floating button in the corner of the screen.

How could you prevent a single element from resizing in the browser, and make it stay the same size at all times?

bobsoap
  • 3,865
  • 6
  • 26
  • 42
  • I was unaware that CSS/HTML was modeled after nature and the universe ;) – bobsoap Mar 05 '13 at 22:05
  • 3
    I am also working on this problem. Ali Bassam's answer is bullsh. This effect is predominately used in responsive mobile web ads, and mobile UI kits with fixed header footer elements. ad example: http://www.adform.com/BannerTags/Views/Test/Test.aspx?key=MTI5MTI5MQ== – kevzettler Mar 13 '13 at 19:19
  • Switching from `fixed` to `absolute` on zoom is the way the go. Like this you leave device or browser zoom as the user wants to use it, have the website accessible for users who want to use the zoom and you don't have to worry about zoom level or future browser or device/OS changes regarding zoom functionality. – lowtechsun Jan 24 '17 at 12:53

3 Answers3

25

Demo to this answer
Dialog widget library I wrote based on this answer.
Demo for the dialog widget Try it on mobile, zoom around and tap the link.

While the gesture event seems to hold some metadata about the scale factor of something, we might be better off in control and find it manually. Since we want to keep the effect up while the user moves around live, we need to recalculate during every scroll event.

window.addEventListener('scroll', function(e){ /* coming next */ })

We calculate the zoom factor and apply it to the rescaled element as a CSS3 transform:

el.style["transform"] = "scale(" + window.innerWidth/document.documentElement.clientWidth + ")";

This will rescale the element back to zoom 1 ratio relative to the current viewport zoom, but it's likely it is still incorrectly placed on the page. This means we have to get new values for it's position. What will actually happen on screen is dependant on the element's CSS position value, fixed will behave differently than absolute and on mobile Safari specifically, fixed position has an added smoothed out effect while the page is zoomed, which creates some inconvenient problems for this cause - I would suggest having a 100% content height element as a relative parent for your intended scaled element, then in your script, position your element absolutely inside of the parent. The following values work for this example demo:

overlay.style.left = window.pageXOffset + 'px';
overlay.style.bottom = document.documentElement.clientHeight - (window.pageYOffset + window.innerHeight) + 'px';

You might also pay attention to using transform-origin CSS property depending on from which anchor point you want the scaling to take effect - this has a direct effect on alignment.

rwong48
  • 39
  • 8
mystrdat
  • 3,239
  • 1
  • 28
  • 36
  • Amazing! Does this work on android or windows mobile? – mozgras May 22 '14 at 03:26
  • 2
    @mozgras The example should work on iPhone, although it likely has a lot of real world problems unadressed. Since the answer, I have created a custom modal dialog that rescales itself and repositions on the screen based on this whole idea. I think the repo is currently private, but I'll try to make it public asap. Here's the [repo](https://github.com/salsita/jquery-ui-scalebreaker) and here's a public [live demo](http://mystrd.at/testing/jq-scalebreaker/demo/) of it - in fact you can probably just get the code from the demo itself. – mystrdat May 22 '14 at 16:38
  • @mystrdat what corners does your library cover which this original answer does not? Also, you mentioned "it is likely to have a lot of real world problems unaddressed". Can you elaborate? I have tested your technique on many devices and it works surprisingly well – ido Jun 17 '14 at 16:27
  • @ido Issues like scale ratio being calculated wrongly on browsers with physical scrollbars, differences between how Android stock and Safari treat `position: fixed` elements while zoomed, no fallback for websites that aren't mobile friendly.. There were quite a few as I learned. The library is tweaked and optimized towards being a well working dialog widget that utilizes this effect and not just a short proof of concept as the demo code (since we needed such a dialog developed internally). I suppose an off-shoot library could be made, that takes any `position: fixed` element as source. – mystrdat Jun 18 '14 at 17:58
  • It doesn't work on desktop because you can't zoom the viewport on desktop. If you're just using the browser scaled zoom, it will not show any difference. – mystrdat Sep 13 '14 at 10:42
  • Interesting solution, but we can say "it works 50%": the supposedly "fixed" element **doesn't stay fixed** while pinch-zooming (it is zoomed/enlarged), but its position/zooming factor will be reset to initial after a few hundreds of milliseconds when the pinch-zooming is finished. – Basj Feb 20 '18 at 23:24
  • @Basj Not sure I understand the problem from your description, could you perhaps record the issue in a gif? – mystrdat Feb 21 '18 at 16:51
8

I'm looking to do the same thing that @bobsoap was trying to do BUT My solution is the following:

1. Disable zooming in your viewport tag:

<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1" />

2. Use a plugin like: TouchSwipe.js:

https://github.com/mattbryson/TouchSwipe-Jquery-Plugin

And only zoom in the Div or divs that you want & suit to your needs.

I have 2 divs on a page (left & right) The left div has a fixed scrolling menu and the right has small text & images. I want to pinch/zoom and have only the right div zoom so that the user can read the text better if necessary. Rather than make the entire viewport zoomable and disable zoom on my left div, I'm doing exactly the opposite: Make only my right div zoomable via TouchSwipe plugin.

I'll share my code when I'm done if anyone is interested in how I implemented the TouchSwipe plugin.

Community
  • 1
  • 1
Max Knox
  • 127
  • 1
  • 2
  • This looks like a good way to do it. How do you use the TouchSwipe? – Konservin Nov 25 '14 at 08:23
  • Hi, I was wondering how did you use TouchSwipe.js to enable a zoom effect similar to the normal browser behavior...can you explain how did you achieve this? – user3098549 Mar 09 '15 at 18:00
  • 1
    pinch is not detected in the pinch demo on ios. – FlavorScape Jan 30 '16 at 03:25
  • I would refrain from disabling zoom in meta tags. Apple decided to override this tag, users should be allowed to zoom. Coming up with a good way to handle zoom on fixed elements is a tough one indeed. – lowtechsun Jan 23 '17 at 09:47
  • Could you post a runnable code snippet to see how it works @MaxKnox? – Basj Feb 20 '18 at 23:15
-4

You're missing a width attribute and you can use things like max-width and max-height to help keep the box the size you wanted. However, zooming allows the user to get pretty granular with a page, so there's always going to be a chance they have that issue.

#fixed { height:150px; width: 200px; max-width: 200px; max-height: 150px; position:fixed; top:0; left:0; z-index:10000; }
Tammy Shipps
  • 726
  • 3
  • 13
  • Thanks for your answer, but I believe you might have misunderstood the question. Max-height doesn't do anything special in the case of zooming. Also, width is not important for the question, nor is it absolutely required for block-level elements. – bobsoap Mar 05 '13 at 23:44
  • 2
    I think you're misunderstanding the problem - zooming is a phone-level function, not a code-level function. You can't control it. – Tammy Shipps Mar 06 '13 at 02:42
  • 2
    No need to get defensive, Tammy. I see that you now understand the question I'm asking. Your original answer doesn't reflect that. The phone's zoom function is indeed what I'm after, only that I'm hoping that there is a way to control it. Hence my question. Thanks again. – bobsoap Mar 06 '13 at 12:34
  • 1
    yeah it's pretty terrible, i've found no solution to keep a fixed nav from scaling while having non-fixed elements scale. I have a really valid use case to have fixed nav and zooming content. i've tried every variation out there. – FlavorScape Jan 30 '16 at 03:30