Images are not rendered until after scrolling stops on iOS (PhoneGap) - javascript

I am working on a PhoneGap web app for iOS.
I have an implemented an infinite list, where as you scroll down the page, new elements are loaded from the server and added to the bottom of the page.
Each element added to the page includes images that are loaded asyncronously.
However, the images do not actually appear until after scrolling stops. This makes things appear sluggish, even though they are not - ie until I remove my finger from the device.
Does anyone know of a workaround for this problem?

This funky work around for safari will do the trick for you:
*:not(html) {
-webkit-transform: translate3d(0, 0, 0);
}
This will add the translate property to all elements causing the IOS browser to render your off screen elements and give you a silky smooth native like feel. Remember to check your functionality as it can mess with positioning of some elements. If if does add them to the 'not' list e.g:
*not(html, button, img...

This cannot be avoided. Image rendering on webkit-gradient IOS is executed in a dedicated US thread with real time priority.
https://news.ycombinator.com/item?id=3316383

I've noticed the same problem while building my application. The UI consists of many images and it only appears to render what's currently on the screen and when you go to scroll, everything else won't render until it's finished scrolling.
A solution that worked for me was adding an overflow: auto; property to the containers in your layout. When I add it, everything renders and there are no problems when you scroll.

Related

Chrome - background-size: cover;-based gallery causes performance issues

I'm building an app using Vue 2. There's a page that contains a simple image gallery that contains about 20 images and one large page background image.
The background image of the page itself is actually contained in a fixed div element that is position: fixed;, has 100% width and height and uses background-size: cover; to display the image.
All of the ~20 items in the gallery as well are using div elements with background-size: cover; displayed in a 3-column grid and the images are displayed using the dynamically generated background-url CSS property using a Vue computed property. The image paths are never being changed so they aren't being recomputed constantly AFAIK.
The performance of this page in Chrome is abysmal, loading takes forever (those are some high resolution images, though, 4K in width) and once the images are loaded I can somewhat interact with the page but everything is extremely laggy and sometimes the page stops responding completely.
On the other hand, in Firefox and Edge everything is basically buttery smooth, both during the loading of the images and during the scrolling/rendering. The interaction with the app is never blocked.
What I remember trying to fix this is replacing the div elements with regular img tags and loading up images using those. Also, I've tried caching the images, I've tried using static image URLs for testing purposes - the same thing happens every time - other browsers handle it well, Chrome is choking on it.
Here's a screenshot of the performance summary in ~30 seconds, from the moment I click the page URL to the moment that basically everything is loaded and the browser is still struggling to render anything and process any interaction with the page. Obviously the painting phase is an issue here:
Any advice? Thanks!
This question is hard to answer as it is a very specific problem.
You can analyze what is causing this behaviour in chrome by using the developer tools:
Open the developer tools in chrome by pressing "Ctrl+Shift+I".
Go to the tab "Performance".
Hit the record button and do the action which has low performance.
Hit stop and you get a breakdown what happened in the background.
If you don't find the issue with above suggestion, you can post a detailed screenshot of the performance breakdown here, I might be able to help you with it.

Native scroll delaying or stopping JavaScript execution on iOS

This isn't a specific JS code issue, but more the way iOS deals with JS that is causing more problems on my site than most others.
On iOS only (it doesn't happen on Android) if I'm natively scrolling (up/down) and then try to activate some JS just before the scroll has finished (very quickly) then it completely ignores the JS.
I believe that Apple do this so that the UX always remains priority (don't let any crappy JS slow down the user), but in this case it's just a very simple piece of JS that I want to allow to run.
As an example, if a user is scrolling and then quickly presses a tab at the top of the screen that opens a fixed navigation panel then it won't register if the native scroll is still happening. If they press it again (the scroll has finished) then it works.
I'm also using a JS slider to scroll horizontally through images and if I try to scroll left/right just before the native up/down scroll has finished it sort of jumps and isn't good UX. I think it's prioritising the native scroll but still activating the horizontal scroll with some sort of delay.
It's not a massive problem, but not perfect. If everybody slowly navigated the site and waited for the native scroll to come to a complete stop, it would be great. But of course people won't do this.
I don't think preventing the default behaviour will do anything. I have tried to take over the native scroll before on iOS and I just don't think you can.
I think this may actually happen on many sites. I've just tried to find a good example by visiting stackoverflow.com on an iPhone and if you scroll quickly and then quickly hit a link before the scroll has finished it won't register. I don't think text links are as big a UX issue though, but a horizontal slider and big 'open menu' button at the top are much more likely to be hit quickly before the native scroll has ended (as you don't need to read something before you press it, like with text links).
I have various JS scripts on a site that would benefit from this being improved in iOS, so if I can understand a way around it, why it happens, what is going on, then I can apply individual fixes to each of those scripts.
Thanks.
The problem is not that iOS ignores javascript while scrolling (more precisely, while the scroll momentum is active). The problem is that, while that happens, iOS does not really register the position change of elements on the screen. In fact, if you have a handler attached to the scroll event, it will stop firing the moment you stop touching the screen, and then will fire just once when the scrolling stops.
Consequence? You think you're touching a link, but you aren't. The image on the screen has moved up or down, but, to the broswer, everything is on the same position, so, actually, you aren't touching anything (or are touching something different). I got very annoyed when I found this behaviour because, in my case, my page is full of images that are links to a gallery ... and if you touch them while scrolling, the gallery opens showing you not the image you touched, but another (The one that really was on that position when your fingers stopped touching the screen).
Is there a workaround? The only one that I know of is disabling the scroll momentum, but you lose scrolling performance.

Tapping Status Bar in MobileSafari does not work on my test page

I am trying to debug this and can't make any headway. I've got this HTML5 JavaScript library I am building and the test page for it can contain large volumes of output as I am piping console.log and exceptions out into the DOM to quickly inspect them on mobile devices (it is the only way I know of inspecting state on an Android device for instance)
Here is the page. So long as I don't push up broken code while I work on this you should be able to produce plenty of debug output which will be pumped into the <body> thus allowing the page to scroll. Note also to toggle the visibility of the big blue debug panel you can tap the header text at the top of the page (like a button).
The issue is specific to iOS: Tapping the iOS status bar does not work in either portrait or landscape modes, and I am not sure what it is I have done with JS or otherwise that has disabled this quite handy feature.
Use of -webkit-overflow-scrolling: touch appears to be the culprit for iOS6 here. It actually looks like iOS5 is less broken w.r.t. this issue.
I think there may be a way to work around the issue by dynamically setting -webkit-overflow-scrolling: touch on the elements that need it by catching touch events on them. Or just leave it off as they still remain usable (just have no momentum).

Rendering bug in WebKit browsers

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.

How can I make a parallax scrolling site that works on iOS and desktop?

Before you say this isn't possible, I know it is. Here's an example: http://victoriabeckham.landrover.com/INT
The main problem is that iOS freezes DOM manipulation on scroll, so you have to use some sort of technique to overcome the problem. The parallax plugin I was hoping to use is stellar.js, but the issue I am running into is that the "iOS demo" for that plugin isn't really usable on a desktop. I fiddled with it for 3 hours this morning, and couldn't get a setup that works correctly on both iOS and desktop.
I need some ideas, either a technique to configure stellar.js to work the same way on both (I'm not sure if that's possible), or another library that works on both, or maybe some insight on how I could program a workaround myself.
Any help is appreciated.
Step 1: Create and object like this
{
startFrameNumber: {
//first obj
id: idOfElement
duration: howeverManyFrames
startLeft: whatever
endLeft: whatever
startTop: stillWhatever
endTop: whateverAgain
},
nextStartFrameNumber: {
}
}
Step 2: Make the page unscrollable via CSS, ie 100% height and width with and overflow: hidden
Step 3: When the user scrolls (via custom scrollbar, keyboard action, or touch events) advance the animation x frames based on how far they scrolled or whatever. If your animation object you created has a key [frame] then add that to the queue of things that are visible and moving, and move all those things in the queue to their appropriate places and/or remove them from the queue of active objects
That's it. The function for moving things around should be pretty straight forward, except getting the animations smooth will take a little playing around with.
Simply scroll each layer of parallax effect manually and control them yourself without relying on browser's page scrolling.
I've successfully implemented cross device/browser parallax scrolling with the help of the Zynga Scroller js library.
It takes care of one of your main concerns which is the interoperability of click and touch events and scrolling on mobile webkit devices – this allows you to manipulate the DOM as you scroll.
Then, to create the parallax effect you have three options:
Simulating a real-world 3d parallax by using 3d transforms (with a parent/wrapper element that controls perspective and transform origin).
Using a 2d parallax library such as stellar.js or skrollr
Building your own parallax scrolling algorithm.
Here's a quick demo (using existing sample code) of option 1 showing how smooth parallax scrolling would work across desktop and mobile devices. Of course, you're limited to devices that have support for 3d transforms. Note that the Zynga Scroller works via click/touch and drag – it should probably not be used as a dekstop solution as the only thing that would be required is overflow: scroll in CSS.
Have a look at the jQuery-Plugin "Scroll Path" http://joelb.me/scrollpath and combine this with different layers and speeds. You will have recognized that the scrolling of the example page is not just a vertical parallax stage but also moves layers horizontally while you scroll up and down. This is possible with Scroll Path.
Try using http://cubiq.org/iscroll-4 and stellar.js together.
Do your parallax stuff for desktop normally and then add a 'touchmove' Event Listener to fire the scroll event:
document.body.addEventListener('touchmove', function(){$window.scroll()}, true);
Tested and working on iPad 2 with iOs 5.1.1

Categories

Resources