I am currently developing a hybrid mobile app which makes use of -webkit-overflow-scrolling: touch; on the "content area" to provide smooth scrolling.
I have hit somewhat of a road block however when using this feature. Upon scroll (I check with an .onAnimationFrame loop) I check the .scrollTop position to see if any movement has occured so that I can let various components within the application know of this so they can perform certain actions (Use case examples may be parallax scrolling, controlling culled rendering etc.). This is all well and good when testing in a desktop browser (Ie. Chrome 41) however when debugging within iOS Safari OR iOS UIWebView the scrollTop position seems to be cached when there is a large amount of movement (Eg. a user flicking the view)
This caching means that other elements expecting to know the exact current scrollTop value will fall behind and the view becomes out of sync.
My presumption is that overflow scrolling forces rendering onto the gpu so I'm wondering if there is any way to get around this or to force invalidation of the cached scrollTop value.
DEMONSTRATION: http://jsfiddle.net/skpmkjea/ (load up in safari on an ios device and connect to debugger to see console log of scroll top positions)
Things I've tried:
Forcing an empty element in and out of the root body to try and force a full page update to re-calculate the scrollTop value
Using a container div within the scroll element and checking for the bounding box updating .getBoundingClientRect() but this seems to have the same cached values
More info (I'll add more if it would help anyone):
UIWebView build with Cordova
My main test target is iOS7
The issue exists but is much less noticeable (ie. cached value invalidation appears to occur at intervals) on android 4
Related
Is this a Firefox bug, or am I doing something wrong?
Changing the top value of a positioned element many times (for instance while a user drags an other element) works on all mainstream browsers as far as I could test, but Firefox which seems to debounce these changes.
Here's a working example under Chrome:
And a failing one under Firefox (notice that the attribute is updated in the dev tool, but the page stays out of sync until the events stop being fired):
You can try it at http://ec2-13-58-57-41.us-east-2.compute.amazonaws.com:8080/components
Quick note:
You might tell me to just use the browser's scroll so here's my reason for doing what I described:
I find it practical to have a Scroller React Component wrapping content:
it makes it easy to control the style of all of my scrollbars for any browser, depending on a theme and on the state of the application (like displaying them only when the content is hovered for instance)
it provides a single development interface for regular scrolling and virtual scrolling
http://jsbin.com/nesiside/1 (code is available http://jsbin.com/nesiside/1/edit)
If you scroll down in the document and click the "Lock/Unlock" button, an overlay with text will appear. You'll notice that the scrollbar length has been changed to accommodate the overlay height, not the original page height. Click "Unlock" in the overlay, and you return to the original page, in the previous scroll position.
System works great on desktop browsers, and on my Android phone, however, on iOS there is a rendering flash flash when the overlay is triggered or removed. Ultimately, I believe it is the fault of the scrollbar changing.
I've attempted the usual tricks to resolve iOS rendering issues (webkit-backface, transform3d), with no success.
Apparently, showing the content and hiding the overlay (or vise versa) was to much for the iPad 4 to render at once, causing the flash. This is odd because I tested it on an old Kindle and my Android phone and both are handled it fine with their slow processors.
To resolve the issue, I put the the scrollTop() method (used to return the user to the previous position on the underlying page) inside a requestAnimationFrame function. The result isn't perfect (content can be screen scrolling for a fraction of as section), but it is a much better result than an entire page flash.
I have an element with position fixed (pinned to any corner) on a page (which I do not necessarily have control over the meta viewport tag - it is an embedded widget for third party sites). On Mobile Safari when the user pinch zooms the page at a certain point the viewport becomes larger than the visible area. At that point the fixed position element stays attached to the viewport and is not necessarily in the visible area.
I would like to compare two widths: the width of the visible area and the width of the viewport. I believe the size of the visible area is window.innerWidth. I am not sure how to measure the viewport.
I have been trying to see the relationships between:
document.documentElement.clientWidth
screen.width
window.innerWidth
window.outerWidth
...But have not been able to see anything obvious.
This is butt ugly but it does show some code that almost works (view on iOS to see it working. Use a desktop and click edit at top right of page to see or edit code):
https://jsbin.com/jopamu (iOS only)
The trick with the "overzoom" calculation is nasty but it does compensate somewhat for the multiple viewport zooms. It is a complex problem to solve because there are competing issues:
pinch-zoom
zoom due to input focus
the "position:fixed" zoom
potentially the OS (accessibility) zoom
The possible solutions I have found are:
Position the menu using the calculations above and position:absolute - updating the left/top in onscroll event. Has ugly juddering (can improve a little by hiding and only showing when zooming/scrolling finishes).
Position the menu using position:fixed but change the left/top to correct the menu position as zooming/scrolling occurs. Much less judder but I couldn't quite get it 100% reliable (some race condition).
Not suitable for your case (and highly unrecommended due to risk of breaking things): you can prevent pinch zooming and iOS10 double-click zooming by cancelling default on touchstart. Difficult because it needs many other workarounds so normal touch works, and needs synthetic scrolling and zooming (but has ugly side effects such as preventing scrolling working sometimes and also interferes with accessability e.g. if voice accessability turned on etc etc).
If you just want to see the widths then use the older version:https://output.jsbin.com/jopamu/6
In the project I currently work on we experience very strange rendering issue. The worst thing is that this issue emerges completely spontaneously and after several days of testing we haven't managed to find the sequence of actions wich would reproduce this issue. Here is an explanation of how this bug look like. Here is a screenshot of how the page should look like:
But instead of this after some manipulations content block pops up so only the part of the content is visible and its look like:
The most strange thing is that such a position of the block is not based on values of CSS properties as shown by Web Inspector.
As you can see the CSS properties are ok, while the position of the block is not. This fact suggest me that it could be some rendering bug of the WebKit engine
The project is built using Ext JS 3.4 and it is a classical one-page web application. This issue was seen in the last versions of Chrome and Safari on Mac OS 10.7/10.8. Though due to the spontaneous nature of this issue it might be present in other browsers and platforms too.
Any piece of advice on how to debug such issues or how it could arise is welcome.
Please check if any of your code or Ext JS's code is using scrollIntoView method, we have seen similar issue when scrollIntoView is called on any element that does not have overflow set to auto and it is inside an clipped element that is probably placed relatively positioned.
It seems bug in webkit because it scrolls clipped element which is not happening in other browsers.
I also see two elements in same hierarchy which has overflow set to auto. And scrollIntoView is scrolling wrong element.
Chrome and safari on Mac are having problems with scrolling. If the element has been scrolled and the content changes, the scroll position is kept even if the content is not high enough to require a scrolling.
The work around we have found in our application is to resize the container (the one that has the scroll) so that it has the scrollbar (or else you cannot play with the scrolling properties) and then reset the scrolling, and the height.
$(container).css('height',1).scrollTop('1').css('height','');
Here is how we do it in jQuery. You will not even see a flickering :)
I am not sure if it is the problem, but this thing kept us on our feet for a while.
i went through the same problem while working with a sencha touch 2 app and because thats same as ExtJS i have a solution for you
this probably is a bug in the framework and this happens when the ExtJS renders the application before the browser populates mayb the correct window.innerWidth and window.innerHeight and thus the viewport cannot take the correct width and height. this also explains the randomness of the event. This becomes more prominent when used on mobiles probably because of the limited resources and slow response.
the solution that i took to handle this mayb isnt a good one but i couldnt find a better one considering is a glitch in the framework itself
i poll for the correct height and width of the browser for around a sec after every say 100ms for the correct height and width of the window and if i find that the height OR width of the viewport isnt same i re adjust it. because you are working with ExtJS and app would run on high powered systems(as compared to mobile phones) i would recommend a smaller interval and then to be safe a larger time period to which it polls.
heres the code that i use currently edit according to your needs
var aId = setInterval(function () {
if (Ext.Viewport.getWidth() !== window.innerWidth || Ext.Viewport.getHeight() !== window.innerHeight) {
Ext.Viewport.setSize(window.innerWidth, window.innerHeight);
clearInterval(aId);
}
num = num + 1;
if (num > 10) {
clearInterval(aId);
}
}, 100)
i currently use this code inside the launch function of the app. but you can also use this inside the show event of the viewport for which you should keep the interval time to minimum possible to avoid any lags.
with this if you think this app might be used on devices where the window height and width would be changed by the user (like that of mobile browser when the orientation changes or if you think user would change the height and width of the browser window). then just copy & paste the same code piece inside the viewports resize event so that it also polls and resizes viewport when the size of the viewport changes.
Did you try adding a clear:both; block after the toolbar div ?
<div style="clear:both;"></div>
#bjornd it's pretty hard to debug without any code :)
Is the toolbar positioned and has the content an ID that's called in the URL?
In other words: is there some link (e.g.) that triggers #content and has no preventDefault() etc? This would scroll the page probably.
I dunno, this was the first thing that came to mind.
It could also be the toolbar content that is (for some reason) no longer cleared or some change in the content's top position (relative to another changed/removed element?)
Try and create a stripped-down test-case that contains the simplest of code but still triggers the bug. If you post that (through e.g. a Fiddle etc) we can have a proper look.
It might be a css issue;
I've had a similar issue using equal height divs by setting a padding-bottom: 99999px; and margin-bottom: -99999px;. Which workes fine in all cases, except when you use hashtag anchors to jump to a div further on the page. Jump down.
In that case the top of the page clipped and started with the div I wanted to see.
Since you say the problem is pretty hard to track, this might be something to have a look at. The solution was to remove these 2 css lines and use another method of setting div heights.
On iPad I cannot scroll a web page. It works fine in Safari, Chrome and Firefox on OS X.
The page has an area in which content can be scrolled only horizontally. It consists of a container div which has width = 100% and height = (100% - 40px). I am setting the height by a JavaScipt function which is triggered by window resize events. Inside this container is another div with the width of the content (very wide, to avoid line breaks). Inside that is the content.
CSS properties of the container are:
overflow-x:scroll;
overflow-y:hidden;
white-space:nowrap;
See the page and full source code here: dcfoto.de
On iPad, scrolling is not possible. What am I doing wrong?
By the way: resizing also does not work properly on orientation change. Maybe that's connected.
Unfortunately a two-finger swipe needs to be performed, and even then it is not responsive (when compared to the default one finger swipe scroll).
There are quite many javascript solutions out there, (sencha touch and iscroll being the most promising and advanced)
I would recommend http://cubiq.org/iscroll-4 which is hands down the coolest touch-scroll script out there. It also works for android, but quite more sluggishly since the default android browser albeit webkit based doesnot support css3 3d accelerated properties as good as the mobile safari one.
If I were you I would check for the user agent of the user, and deploy that script for android and ipad/iphone users.