-webkit-transform: scale breaks down when zoomed in on iOS - javascript

EDIT:
These issues appear to have been fixed by iOS8. Consider this issue an iOS7 and earlier bug.
I've got some content (subject to CORS) that I'm serving in an iframe, that I want to be always stretched across the bottom of the browser window. I need this content to keep the same aspect ratio and fill the entire width of the browser, otherwise things will look weird. Because I don't have access to the iframe's contents I'm using -webkit-transform: scale to properly size everything properly.
I'm calculating the scaleFactor:
width = 600; // this is the original width of the iframe's contents and never changes
scaleFactor = window.innerWidth/width;
Then I set some CSS based on that scaleFactor, whenever window.innerWidth changes size:
$container.css({
'width': (width * scaleFactor) + 'px',
'height': (height * scaleFactor) + 'px',
'padding': 0
});
$iframe.css({
'-webkit-transform': 'scale('+scaleFactor+')',
'transform': 'scale('+scaleFactor+')',
'-webkit-transform-origin': '0 0',
'transform-origin': '0 0'
});
This works perfectly everyplace except iOS where it starts to break down if you zoom in too far. The iFrame starts to drift off the page and isn't near wide enough. I have no clue what's going on here.
Images of what I'm talking about: Good scaling, Bad scaling.
I've got a test page setup here that clearly demonstrates the problem on any iOS.
Anybody have any ideas?

Here's the result of my extensive investigation before I gave up.
There are two major problems involved in applying transform: scale to content inside iframes on iOS. The first was what I pointed out in the original question, that content starts to drift away from it's specified location on the page if you are using fixed position elements. It works up to a point that seems to be based on the original size of the element, the scale factor, and presumably the viewport width. In my tests a large element might scale and position perfectly when scaled at any factor greater than 0.85. A small element might be positioned perfectly so long as the scale factor is at least >3.5. It seems almost random, so I didn't bother determining what the exact point was.
I didn't try this on relatively positioned elements, but I'm assuming they function similar to fixed position elements.
There is a rather kludgy workaround for this involving using absolutely positioned elements anchored to the bottom of the page using scroll offsets and innerHeight. i.e.:
container.css('top', (document.body.scrollTop + window.innerHeight - container.height()) + 'px');
container.css('left', document.body.scrollLeft);
And updating this on every drag, transform, pinch, resize, etc. There is some weirdness involved with this method (iOS doesn't update scroll offsets until after a drag has completely stopped) but it's workable if you absolutely had to do it.
However, even though that's a possibility, when you scale content inside iframes on iOS, if you have ANY anchor tags (or other elements that need to be clicked on), the clickable area stays unscaled. If you have an image in inside an anchor tag that's 200x100 and you scale it 2x, the image will be twice as big, but the anchor will only respond to the first 200x100. Using the iOS simulator, if you double click on an image outside the clickable area Safari is even helpful enough to darken the original bounds so you know where you could have clicked. It's pretty much a deal breaker if you want to display anything other than text/images that don't require clicking or other inputs. More information here:
CSS3 Transform scaling issue on IPad Safari
"-webkit-transform: scale(2)" doesn't affect click area of Facebook Like Button (on iPad)
Until Apple fixes these long standing bugs in mobile Safari, it seems that trying to scale iframe content using webkit-transform isn't a viable option unless you are only targeting Chrome.
Edit:
Demo of scaling issues here.

Combo of iframe, transform scale, and ios is tricky.
There are bugs with transform scale. Not always in your control.
You can try zoom property instead of scale, and use scale for firefox where its not supported.
I don't have ios here so I cant check but it often works wonders. Though you may have issues with line breaks in text with zoom.
zoom solves this bug in chrome

Related

Why does webview report different screen size, and can I disable this

So basically, I created an Android WebView, in a 720 x 1280 screen. However when I evaluate screen.width and screen.height, the response is 360 and 640.
I understand that this may be partly so that content is displayed on a readable way, but, when I tried to set a static width to the WebView, like 1000px x 1000px, the Javascript still evaluates the same.
Is there a way to disable this, so that the content looks same as it would on a desktop screen, and the screen.width and screen.height return the real phone resolution or the one I manually set in the XML.
A Crosswalk (based in chromium) solution is also acceptable, even if it includes changing the source code, if WebView solution is not possible.
If I understand you right, you want to show websites in desktop mode, not in mobile mode. To achieve this you can use this custom subclass of WebView: https://github.com/delight-im/Android-AdvancedWebView
It has a method setDesktopMode(true) that will do what you want.
This maybe be due to the pixel ratio of the device.
see this thread for a detailed explanation
Note that different android screens will have different ratios depending on their resolutions. My experience is with iphone / ipad; and my solution was to detect the pixel ratio and use that as a multiplier for positioning all elements.
Also If feasible, I recommend positioning based on a multiplier rather than a fixed value. For example:
x = 0.5 * screen.width * xPixelRatio
will give you a relative position at 50% (i.e the middle) of the screen. By positioning elements in this way as long as your aspect ratio is the same the elements will always stretch to fit properly, and you can adjust for different aspect ratios by changing the xPixelRatio & yPixelRatio variables.

Fixed navigation/header and keyboard scrolling

Page scrolling using the keyboard (PgUp/PgDown, Space) sometimes gets difficult if there are elements with fixed positions at the top of the page, e.g. navigation bars: content that was not visible at the bottom of the viewport might be hidden by the fixed elements after scrolling.
How to address this problem? Do browsers calculate, how far they should scroll? I observed different behaviors for different browsers and also for the same browsers on different pages (for example, Firefox leaves about 80px of old content on http://www.sueddeutsche.de/, but far less on http://www.taz.de. Chromium leaves much more content.).
Is this a problem at all, i.e. does anybody beside me use the keyboard to scroll a web page? Do you know any statistics?
To illustrate the problem, I created a Fiddle:
https://jsfiddle.net/x7hj8c4m/
Try to scroll the content using Space on Firefox. The fixed element will cover text that was not yet visible before scrolling. If you add left: 0, it works.
Very interesting observation.
Firstly, pressing space is equivalent to pressing PgDn. And when PgDn is pressed, the page should scroll vertically by roughly "one page's worth of px". As shown by the OP's fiddle, Firefox in particular calculates this value differently, depending on whether it detects a fixed header.
From my own tests on IE, Chrome, Firefox, I deduced that:
Without a position: fixed element, Chrome and IE scroll down by ~87.5% of the document height; Firefox scrolls down by document height - scrollbar height - ~20px.
With a position: fixed; width: 100% element at the top-left of the screen, Firefox intelligently understands that the element perceptually reduces the document height, and so applies: document height - scrollbar height - fixed element height - ~20px. The condition appears to be quite specific: the element must be fixed exactly at the top-left of the document's box model with full width in order for it to work. The other browsers (Chrome, IE) don't perform such compensation, and performs the standard 87.5% scroll.
I don't know if this is relevant, but it might have something to do with support for position: sticky.
Scrolling by keyboard is a pretty basic behaviour that probably doesn't interact too much (if at all) with the DOM, so expecting it to account for fixed elements is probably too much. There seem to be browser-specific predefined increments (I have no idea if or how they can be customized), but note that the increments are usually smaller (presumably small enough) when you use the up/down arrow keys.

Prevent Object from Zooming

i'm writing a website on which everything should be able to be zoomed except of one object.
Is it possible to prevent only this object from being zoomed (typical pinch gesture on ipad, iphone)? (I know you shouldn't do this because zoom should entlarge everything on the page... but i don't know a way around.)
It has only to run on mobile safari.
Thanks for your help.
In order to do this, you need to be able to detect the zoom, which is not possible... at least, not directly. This post introduces a rather novel way of detecting the zoom level by using javascript to compare the width ratio of two divs on the page: one with a pixel-defined width and the other with a percentage-defined width. When the user pinches/zooms, the pixel width will not change, but the percent width will, so if you use javascript to detect the offset width of these two objects and get the ratio you can get the zoom. Then, if the ratio is, say, 150%, you can change change the width and height of you "fixed" object (using javascript) and multiplying each by .66666.
The major challenge you face here is that you cannot detect the moment of a zoom, so you'd have to use a setInterval() call to constantly be checking the ratio of the two test divs.

Scaled Transparent PNGs lose anti-aliasing after jQuery animation in Webkit browsers

I have a script that lays out these circular icons on the map, you hover over them, they spring up, text appears, etc. The icons are scaled relative to their position on the map, ie, the distance from 0 on the y-axis. I've tried to set the scale through CSS's width and height attributes and through the html width & heights on the img tag and still have the same problem:
Basically, in their dormant state, such as when the page is first loaded, or the user flicks between tabs, the images (trans' PNGs) are anti-aliased. However, when the hover() function, and thus the animate() function, is invoked, the images suddenly become jagged and horrid. I've noticed that this behaviour doesn't exist in firefox but does in safari and chrome. I don't know whether this is to do with Webkit, jQuery or just javascript itself but maybe someone could shine some light as google resulted in nothing. Any thoughts? :)
Please also note that the bottom left and bottom right icons look fine in both attached screenshots- they're unscaled ones!
Thanks a lot :)
Matt
i can only guess on this, but my assumption is that gecko and webkit use different scaling algorithms for images. thus it has nothing to do with javascript, jquery or png at all.
in fact, the image still has antialiased edges even in the webkit screenshot. (you see that when you zoom in)
the border is just messed up which is usually the result of a bad scaling algorithm.
try the following to confirm this assumption:
<img src="youricon.png" width="90%" height="90%">
and compare the result in the two browsers. you should see the same problem.
possible solutions:
make a smaller version of the image and replace image with the smaller one on hover instead of scaling it.
use a scalable vector graphics format like SVG for your icons.

Issue with decimal place pixel alignment

So a fellow StackOverflow-er wrote out some jQuery based Javascript for me a few days ago.
It works, but there's an annoying issue with it and I wondered if anyone could help out.
The JavaScript is calculating a margin for alignment purposes. The value it calculates is is not always an exact pixel, e.g sometimes its 14.4 etc. In Firefox the issue does not exist, but in other browsers such as in Safari or Chrome when the margin is being calculated (as the screen is re-sized) the far right hand side box 'jumps' and never quite stays against the edge of the container.
As I said above, in Firefox it does not 'jump', and this is the effect I was looking for.
Is there anything that could be done to stop this 'jumping' effect or is it completely related to the browsers rendering engine and out of my control? :(
This JSFiddle contains the code/demo : http://jsfiddle.net/m4rGp/1/
(Try resizing the browser width in Firefox then Safari/Chrome and you will notice the jump on the right)
Any reply's are really, really appreciated! Many thanks
This is because of the rendering engine only. There are no decimals in pixel. 1px is the smallest addressable screen element. So before changing the margin add a Math.round
$(".barModules li").css('margin-left', Math.round(dynMargin) + "px");
yet the bouncing will be there because the element is positioned in such a way that it is bound to its left (reference). When it sees the attribute margin-right:0, it tries to activate that one too ... but due to its margin-left being set and positioning based on left .... it is bouncing like that. like a debounced function call.
If your aim is to get a dynamic margin, then you have to adjust with this, else go for a fixed width page with centered elements and you don't have to worry about overflow problem

Categories