Mobile Safari: inertia scrolling on body AND minimal UI behavior? - ios

This question requires some explaining, so please bear with me.
Contrary to popular belief, inertia scrolling (the very smooth 60fps scrolling) is not enabled on web pages in Mobile Safari by default. As it makes a world of difference in user experience, I have enabled it by dynamically applying this CSS to the HTML and BODY element of the page, after a Modernizr test for iOS specifically:
<style>
.touchscroll {
overflow: auto;
-webkit-overflow-scrolling: touch;
position:relative;
height:100%;
}
.touchscroll body {
height:100%;
overflow: auto;
-webkit-overflow-scrolling: touch;
position:relative;
}
</style>
The above basically makes the body element a scrollable element and by means of -webkit-overflow-scrolling: touch, one gets the smooth intertia scrolling effect on the entire page. Some more background on this solution can be found here (disclaimer: article by myself).
It works, so far, so good. The problem is that this solution effectively disables another highly desired behavior of Mobile Safari: normally, when scrolling down, it will make the address bar smaller, and hide the bottom bar of the browser entirely. They re-appear when scrolling back up.
Unfortunately, the above technique disables this for some reason. Yes, we've got super smooth scrolling, yet the browser bar is always large and the bottom bar permanently stays visible, both taking up valuable space.
My question therefore is, can I have both? I want the super smooth scrolling on the entire page, yet I also want the default hiding behavior of browser elements when scrolling.
An example of a site where I am using this is here:
http://www.jungledragon.com/
If you open that in Mobile Safari, you will see the smooth scrolling, yet not the hiding of browser elements when scrolling down.

I think you're setting both the <html> and the <body> element to scroll. You should apply these CSS rules to 1 element you want to be able to scroll.
So either the html or body, not both.

Related

Cordova iOS - transition causes page flash

I am developing an application in Cordova, where the user can switch between a few 'screens', which are just hidden divs brought into view by a transition.
The scrolling on iOS has been terrible, so I added -webkit-overflow-scrolling: touch to the container element and it sorted out the scrolling issue I had.
However, since then the page transitions cause the pages to flash each time the application moves to a new page.
Here is my CSS
.scrollable {
overflow: scroll;
-webkit-overflow-scrolling: touch;
}
Once a button is pressed to proceed to the next page it uses this javascript code for the transition
this.lastScreen.getLayout().getElement().css({
'left': -$(window).width(),
'transition': 'left 0.25s ease-out'
});
this.currentScreen.getLayout().getElement().css({
'left': 0,
'transition': 'left 0.25s ease-out'
});
<div class="container scrollable">
//screen content here
</div>
If I remove the -webkit-overflow-scrolling: touch; from the scrollable class it works fine, no flash happens. However, the scrolling of the page is terrible.
I am running iOS 9.3.1. I read around and found out this may have been an issue from iOS 8+ but can't really find a difinitve answer to help me
I suggest you to use native transitions with cordova´s app.
http://plugins.telerik.com/cordova/plugin/native-page-transitions
Add this CSS to the classes that have transitions:
-webkit-transform: translate3d(0px,0px,0px);
It just force hardware acceleration, so it become smoother than the normal one, and probably fix your issues

webkit-overflow-scrolling makes element disappear

I have an app / site where I'm using -webkit-overflow-scrolling: touch; to make the scrolling smooth on iOS.
However, recently it started causing my navbar disappear upon initial load (using iOS) and it only appears when certain elements were scrolled up or down, it makes the navbar completely unusable.
If I comment out the -webkit-overflow-scrolling: touch; then it works perfectly but the momentum scrolling is gone. I've tried adding a z-index hack to the navbar to make sure it's loading on top of everything, I've added a few different display properties as well to see if I could hack the -webkit-overflow-scrolling: touch;, I've even tried adding the items into memory using -webkit-transform: translate3d(0,0,0);, and nothing is working. The navbar still disappears / glitches out no matter what when -webkit-overflow-scrolling: touch; is included.
Has anyone had this glitch before and figured it out? I really don't want to load an entire JS library just to handle my scrolling, but I might have to if I can't figure this glitch out. The non-momentum scrolling feels so clunky and unusable.
I had the same problem. I had a list of items with -webkit-transform: translate3d(0,0,0); that were not showing as soon as I enabled -webkit-overflow-scrolling: touch;. My problem was that I had the elements with -webkit-transform: translate3d(0,0,0); nested inside another div.
In other words, there was a div in between the one with the overflow-scrolling: touch and the children with the translate3d. Didn't realize they had to be direct children.
Once I consolidated my divs directly it stopped hiding the elements and worked perfectly. Hope it helps.
I had the same problem. In my case I was trying to use ::before to display an overlay. I worked on Chrome, but not in Safari/iPhone. I end up not using it in the end, I replace it with ::after

Media queries and viewport width - good CSS fix doesn't work on iPad

There is well known problem with media query width, which is not the same as viewport width in some browsers (WebKit browsers change the size of their CSS viewport when scrollbars are visible). I wanted to fix the problem by moving the vertical scrollbar from body or html to first wrapper div (as described on stackoverflow: https://stackoverflow.com/a/10091608/1647291).
The fix
Here's the fix with CSS:
body, html { overflow: hidden; height: 100%; }
div.wrapper { overflow: auto; height: 100%; }
It moves the vertical scrollbar from body or html to the first div inside body. Thanks to that you don't need to worry about viewport widht in media queries.
The problem
But unfortunately this great method has one bad side effect - on iPad (and possibly on some other platforms too) page can't be scrolled smoothly. After you stop touching the screen it stops scrolling imediately, there's no smooth and slow easing.
This simple solution with CSS is much simpler and better than all those methodes with testing the viewport with javascript. Some of them are described here but they are not reliable or make the site works very slow:
CSS media queries and JavaScript window width do not match
http://github.com/tysonmatanich/viewportSize
http://github.com/ryanve/verge
Is there any way to use this CSS fix and make the iPad scroll correctly?
It is possible you are over thinking this. We make websites all day and this is not a problem. I think that you might be worrying too much about the specific px widths. If 680px vs 693px is a big deal, you are thinking about this the wrong way. I suggest you design mobile first and make a break point whenever it gets ugly (with ems). For sites with short pages and long pages, (causing the scrollbar to appear sometimes and jump between pages when there is no scrollbar) - to just add this and call it a day. Good luck!
html { overflow-y scroll }

Trigger.IO momentum scrolling

Is it possible to add momentum/intertia scrolling to a trigger.io-wrapped HTML5 iOS app?
I'm currently building a basic app, and noticed that the Webview does not respond to the momentum of a swipe action when scrolling through content (iOS 6; iPhone 5). In other words, a slow swipe and a fast swipe end up scrolling to the same section of the Webview (unlike a native app, where said fast swipe should scroll to a farther section).
Is it possible to change this behaviour and make it more native-like? I have tried following these iOS momentum scrolling instructions and modifying the CSS as shown below, however this doesn't work:
html {
overflow: scroll;
-webkit-overflow-scrolling: touch;
}
As a workaround I feel that I could potentially use an intertia-emulating JS library within my webview, however I want to avoid this option if possible.
Thanks in advance!
I don't know much about your app's css, but -webkit-overflow-scrolling: touch; would only give the touch scroll inertia to fixed or absolute elements with fixed height/width in the viewport. Applying -webkit-overflow-scrolling: touch to the body or html element would only work if you did something like
body {
position:fixed;
top:0;
right:0;
bottom: 0;
left: 0;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
We use it in our trigger app to emulate UITableView
Yes. Try out Hojoki where you can see momentum scrolling in action:
https://itunes.apple.com/us/app/hojoki/id525010205?mt=8
You don't have to do anything special to enable momentum scrolling in iOS. If you're not seeing it then it is likely that some styling or 3rd party library you're using as intefered with it.
Yes. I've managed to implement it with iScroll but had to modify the library. I really don't recommend -webkit-overflow-scrolling: touch as it does not render any DOM changes while momentum scrolling is occuring. So if you reize an element as a result of an element scrolling, it looks awful.
Here is my repository where I've added a new callback onScrolling() to alert when the scrolling animation is occurring in iScroll: https://github.com/simpleshadow/iscroll/blob/master/src/iscroll.js
And here's an example I'm using in my Trigger.io app where I change the height of the div during momentum and touch scrolling: http://jsfiddle.net/simpleshadow/wQQEM/22/

iOS5 -webkit-overflow-scrolling causes touch events to stop working

when using [-webkit-overflow-scrolling: touch;], the scrolling area does work well,
but it causes touch events stopping work out of the scrolling area.
Is there anyone had the same problem? Who can give me some official links about this new scrolling feature?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ios5 scroll</title>
<style type="text/css">
header {
background: red;
width: 300px;
height:44px;
}
.scroll {
width: 300px;
height:300px;
background: yellow;
overflow: scroll;
-webkit-overflow-scrolling: touch;
}
</style>
</head>
<body>
<div id="container">
<header>
<button onclick="alert('header');">won't work?</button>
</header>
<div class="scroll">
<button onclick="alert('scroll');">It works</button>
<div>text</div><div>text</div><div>text</div><div>text</div><div>text</div><div>text</div><div>text</div>
<div>text</div><div>text</div><div>text</div><div>text</div><div>text</div><div>text</div><div>text</div>
<div>text</div><div>text</div><div>text</div><div>text</div><div>text</div><div>text</div><div>text</div>
</div>
</div>
</body>
</html>
2011-12-27: I have fixed this problem but I still no wonder the real reason.
In my case, I have several sections in one web page, each section has a scroll area and a header, each time only one section is showed and use css3 animation combined with transform to switch sections. when add [-webkit-overflow-scrolling] in the scroll area of all sections, touch events stop working randomly, so I just add [-webkit-overflow-scrolling] in the section which is showed currently and remove it when the section is hidden. That works well but I still don't know what causes this problem.
I have the same issue, and I can also replicate it every time. I have a page that resizes elements to fit the screen when the orientation of the iPad changes. If at any point the element no longer needs to scroll, it will stop doing so thereafter even if the element is resized back to where it needs to scroll (e.g. flipping back to landscape for me). So it's definitely a bug, but I do have a workaround:
When resizing the element, I'm resetting the -webkit-overflow-scrolling to auto, then setting it back to touch. However, you have to introduce a delay between the two (50ms is working fine, didn't try any lower). So what I did was added an attribute of "scrollable" to the elements, and used the code below (using jQuery):
$("[scrollable]").css("-webkit-overflow-scrolling", "auto");
window.setTimeout(function () { $("[scrollable]").css("-webkit-overflow-scrolling", "touch") }, 100);
Hope this helps!
This is caused by having an <iframe> on the page. Many scripts create <iframes> to do their work including social tracking buttons (Facebook, Twitter, G+), analytics tracking (Google, etc.), and libraries like PhoneGap.
It doesn't matter how the <iframe> is displayed. display: none; visibility: hidden; width: 0; height: 0 does not fix it. If an <iframe> is on the page it will happen, sometimes intermittently and sometimes always.
The only solution I've found so far (which is turning out to not be very workable in a production app) is to delete all <iframes> on the page, create them only when needed (for example, when I need to call a PhoneGap API), and then delete them when finished.
I confirm I saw the same issue on a web app using extensively touch events and list scrolls.
Before iOS5 I was using iScroll, and everything was working fine;
With iOS5, I used -webkit-overflow-scrolling:touch to scroll lists to get faster scrolls.
The consequence is I met random occurrences of touch events no more working on various parts of the app. The issues generally occur after I scrolled a list. it affects randomly elements outside the scrolled area, typically a footer menu.
Reloading the app when in 'frozen touch' state doesn't unfreezes it : to unfreeze it, I had to close the safari tab, open a new one and reload, until I met again the issue while using the app.
The issue is seen on iPad2, iPhone 4, iPhone 3GS, all on iOS 5.0
Eventually, I deactivated the overflow touch scroll and came back to iScroll, and things work well as in iOS4 .
-webkit-overflow-scrolling + CSS3 Animations + Phonegap API calls = touch stops responding.
My phonegap app will work fine until I make a call to a Phonegap API, at which point the touch will stop responding on mainly the first element that has a event attached to it in the current view. A view for my app is body > div.current with the rest of the divs display none.
I can replicate this every time.
It is clearly a bug in iOS5.
Here's a variation on a few of the answers already listed.
My specific issue was that reorientation caused scrolling to stop working completely when -webkit-overflow-scrolling: touch was applied to an element.
Example: Landscape orientation is shorter and needs a scrollbar. Portrait is tall enough that no scrollbar is needed. Reorient to landscape; scrollbar is present but non-functional.
listen for the orientationchange event
do something which triggers a layout change on the scrolling element
ensure that the change is significant enough that the rendering engine doesn't optimize it away. For example, hiding then immediately showing does not seem to do anything. Anything that uses setTimeout() seems to work (perhaps it is the different execution context, I don't know).
Fading in and out works, or hiding and then showing with a short delay works (though it flashes). #Sari's solution for changing the scroll properties works and does not cause any visible redraw.
$(window).on("orientationchange", function () {
// use any valid jQuery selector
var elements = $("[data-touchfix=true]");
elements.css("-webkit-overflow-scrolling", "auto");
window.setTimeout(function () {
elements.css("-webkit-overflow-scrolling", "touch");
}, 100);
});
Note that I haven't tested this fix beyond my iPad 3 other than to ensure that it doesn't cause script errors in Chrome or IE 7/8/9.
In case this is of any use...Incorporating PhoneGap I was using Zepto to append ajax-loaded, scrollable content into the dom. I was then applying a css transition on it. There were no iFrames on the page.
I was experiencing the same issue as mentioned here, where scrolling would just stop working. When I copied the generated code into a separate file and tried that on the iOS simulator - everything worked as expected.
I eventually got it to work by querying the height of the parent container - just before the css transition. By adding var whatever = $('#container').height(); the scrolling worked.
To improve a little bit ThinkingStiff's excelent answer, you can avoid blinking
- if overflow:hidden is set
- if instead of 'auto' value just remove property:
$('.scroll').css({'overflow':'hidden','-webkit-overflow-scrolling':''});
window.setTimeout(function () { $('.scroll').css({'overflow':'auto','-webkit-overflow-scrolling':'touch'})},50);

Resources