jQuery Mobile prevent scroll-to-top before page transition? - javascript

When I click on a list-item, to go to another page, the current page jumps to the top of the screen before transitioning to the next page.
This problem occured in jQM 1.2, and is still not fixed in the newly released 1.3 version.
Does anybody know how to prevent the scroll-to-top, and remember the scroll position when using the back button?
This annoying behaviour is unacceptable, and breaks the whole app experience.
I'm using it as a webapp, on an iPhone 4S, with iOS 6.1.2.

Before I describe your available solutions you need to understand, this is not an error nor is there a perfect solution. The issue is that to animate the transition to another page the viewport has to be at the top of the page so that the current page and the page transitioning in are vertically lined-up.
If you were half-way down a long list on one page (say 1000px) and the page you are transferring to is only a few hundred pixels tall then the current page would animate off the screen properly but the new page would not be visible as it would be above the viewport.
There are 2 viable solutions:
1. iScroll and its jQuery Mobile derivate iScrollview
iScroll homepage: http://cubiq.org/iscroll-4
iScrollview homepage: https://github.com/watusi/jquery-mobile-iscrollview
iScroll is a javascript that can scroll content in a window within a web browser with very similar behaviour to native scrolling on mobile devices such as iPhone and Android. This means you can scroll a window within the browser using native-like scrollbars and physics.
That is also a solution for our current problem. Because of iScroll implementation pages will occupy 100% of page height, no matter how far listview is scrolled. This is also a reason why on return listview will still stay at a same position.
Of course in case you want to implement this solution you should pick iScrollview implementation. You would still be able to implement iScroll, but it would take you much more time.
2. Silent scroll
Official documentation: http://jquerymobile.com/demos/1.1.0-rc.1/docs/api/methods.html
This jQuery Mobile functionality is also the same reason why we have this problem at the first place. Before a page transition is triggered original page is silently scrolled to the top.
In our case, when listview is selected, its position must be remembered (here you will find solutions of data/parameteres storing during the page transition, just search for the chapter: Data/Parameters manipulation between page transitions) before page is changed. In that case, when we return to the previous page we could use pagebefpreshow event to silently scroll to the bottom before page is shown.
//scroll to Y 100px
$.mobile.silentScroll(100);
And here's a working example of silent scroll: http://jsfiddle.net/Gajotres/5zZzz/
More info
If you want to find out more about this topic take a look at this article, you will also find working examples.

I was able to fix this (for iOS) in the following way:
Add a extra container div for the scrolling part. Usually surrounding the scrolling part of your page. In my case right after the header and before the footer code.
Add the following CSS:
.extracontainer {
width: 100%;
height: 100%;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: 0;
padding: 0;
overflow: auto;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
Some of the CSS might be extra but in my case it was to avoid any issues with some other styles that I have using negative margins, paddings, etc.
Also make sure to have the -webkit-overflow-scrolling: touch; to have smooth scrolling.
I hope this helps.

$( document ).on( "mobileinit", function() {
var silentScroll = $.mobile.silentScroll;
$.mobile.silentScroll = function( ypos ) {
if ( $.type( ypos ) !== "number" ) {
// FIX : prevent auto scroll to top after page load
return;
} else {
silentScroll.apply(this, arguments);
}
}
}

For Jquery Mobile 1.4.5 i fixed that by changing this line in jquery.mobile-1.4.5.min.js:
a.mobile.hideUrlBar&&g.load(a.mobile.silentScroll)
to this:
a.mobile.hideUrlBar

Solution to prevent scrool to top is:
body onload="$.mobile.silentScroll(window.scrollY);"

try to use scrollstart to detect window scroll event in jquery mobile, in case you need :)

Related

strange results differing between left and right positioning

This is a strange bug i'm facing, i don't really understand the problem so forgive me for the obscure title.
The problem is I'm developing a SPA style site and i want the content to slide in from the right (when the buttons at the bottom are clicked)
I thought this would be easy, but for some reason it is easy to achieve from the left, using the example below
.page {
right: 100%;}
.page.active {
right: 0; }
https://jsfiddle.net/pphfstos/3/
and less ideally to slide the full width across like this
.page {
left: -100%;}
.page.active {
left: 0; }
https://jsfiddle.net/pphfstos/4/
But when i try to create the same effect as the first example but from the right it not only doesn't work but totally seems to destroy the page
.page {
right: -100%;}
.page.active {
right: 0; }
https://jsfiddle.net/pphfstos/5/
There is other code involved as you can see in the fiddle, but these are the only things that are different between the 3 examples
Can anyone explain what is happening and how to fix it?
Content you position outside of the viewport to the left is actually hidden, and can’t be reached via scrolling.
Content you position outside of the viewport to the right however “extends” the page in that direction, and can be scrolled to.
Remove the overflow-x: hidden from html/body in your first and third fiddle, and you see what I mean – in the first one, the content positioned to the left is hidden, and no scrollbar appears; in your third fiddle however you do get a scrollbar, and the content positioned to the right can be reached via scrolling, moving the part of your page that is initially visible to the left while you’re doing so.
Now, setting overflow-x: hidden removes the ability to scroll using the mouse; but the viewport can still be “shifted” to display that content, for example by navigating to an anchor – and that is what your links are doing. (But because this is an “instant jump” and not smooth scrolling, you don’t see your initially visible content move away, it is just gone instantly.)
So you simply need to suppress the default action of your anchor links in your click event handler:
mainNavButton.click(function (e) {
e.preventDefault(); // prevent event default action
// … rest of your code
– and the effect of the page ”jumping” to the anchor position is gone.
https://jsfiddle.net/pphfstos/6/

How to use angularjs $anchorScroll on div only if div is hidden?

I'm using angularjs to develop a web application. I have several nested div. Each of them correspond to an item that the user can select.
A good example of my div display is in the official angularJs documentation :
http://plnkr.co/edit/qncMfyJpuP2r0VUz0ax8?p=preview
In my code each div have a ng-click="gotoAnchor(x)" event so when I click on a div if it is partially hidden, it pull it up on the page and the user can see all the clicked div.
But I have a header in my page so the first div with an anchor and a click event is not directly at the top of the page. And if I click on the first div, it will scroll and the header won't be visible.
So my question is, is there a way to activate the anchor only if the div isn't fully displayed on the screen ?
If you have an other solution than anchors, I take it.
Thank you in advance.
If I understand your question correctly the issue is that when using $anchorScroll your header is either
a: Being covered up by the div scrolled into frame,
or
b Partially covering up the div that is scrolled into frame.
Either way there are two solutions you should review:
First
make sure you're employing CSS to properly layer your elements, your header (if fixed) should have a z-index that supersedes your divs.
.header { position: fixed; top:0; width: 100%; z-index: 99}
.content { position: relative; margin-top: 10px; z-index: 1;}
REMEMBER Z-index only works on positional elements (See ref)
Second
Employ $anchorScroll.yOffset to make sure your scroll distance is bumped down to compensate for the header height. As seen in the Angular docs, you can use this method in your application:
.run(['$anchorScroll', function($anchorScroll) {
$anchorScroll.yOffset = 50; // always scroll by 50 extra pixels
}])
Update 50 to be the pixel height of your header.
Regarding visibility
There are a few great libraries and directives for checking the visibility of an element - try https://github.com/thenikso/angular-inview as you can specify whether you want to enable an action when only the top, bottom or none of the div is visible.
Note Posistioning the first div correctly on the page will prevent any scroll from being necessary as seen in this plunkr.

Fixed/absolute positioning neglected in iOS when focusing on input

I'm building an app with Phonegap and I have a header which I have fixed to the top of viewport.
header {
position: fixed;
top: 0;
width: 100%;
height: 30px;
background-color: red;
z-index: 100;
}
This works as I want except when I tap a input field and the keyboard slides up. Then the positioning is totally discarded. The header is slided higher up outside the visable view. It returns to its place after closing the keyboard again.
I have read that some mobile browser don't care about positioned fixed and absolute to make sure that a possibly small screen don't get covered with a fixed element. Is this true?
Is there a way around this?
I have tried setting the header to absolute when a input is focused. I read about it here, http://dansajin.com/2012/12/07/fix-position-fixed/. However, it doesn't seem to be working for me.
PhoneGap’s implementation of fixed positioning for iOS is poor when it comes to the virtual keyboard. I’ve tried a number of proposed solutions, including the one you linked to, but none of them worked satisfactorily. Disabling KeyboardShrinksView can cause the input field to get hidden under the keyboard.
I ended up going with this workaround, which simply hides the fixed header when the keyboard slides into view and shows it again after the keyboard slides out of view. I await a more complete fix, but this solution has the benefit of being clean and reliable. The 10 ms delay on show() is enough to prevent the header from momentarily flashing in the wrong place while the keyboard is sliding back down. The 20 ms delay on hide() prevents the header from popping up in the wrong place if the user goes directly from one input field to the next.
$(document).on('focus','input, textarea, select',function() {
setTimeout(function() {
$('header').hide();
},20);
});
$(document).on('blur','input, textarea, select',function() {
setTimeout(function() {
$('header').show();
},10);
});

How to restrict scrolling of a mobile site but allow access to potentially retracted address bar

I have a repo up and running if you're interested in contributing to solutions.
I've run into an interesting problem while constructing a mobile site.
I am setting 'overflow: hidden;' to html/body when a drawer is toggled. This is so the window can't be scrolled, and the drawer - which is scrollable - on reaching it's limits doesn't scroll the page (e.preventDefault(); & e.stopPropagation(); simply don't do the trick).
This all works great. Fantastic if this was a Phonegap app. However - as this is a website, the inconsistent overflow setting creates a usability issue with the browser's 'fullscreen mode'. 'Fullscreen mode' is when the address bar is hidden upon scrolling down the page. When scrolling up the bar will reappear. When toggling the drawer the browser is essentially locked in either 'non fullscreen mode' or 'fullscreen mode'. The latter is the real issue - as users are simply unable to access the address bar - and gives the impression the browser has locked up or something weird.
Any bright ideas as to how (probably with Javascript) a scroll/touchmove could still give the effect of entering/exiting 'fullscreen mode'? I've had a play with the fullscreen API, but that's proper fullscreen, not just the address bar.
here are some screenshots:
site loads, we can see the address bar
site is scrollable as expected, browser enters 'fullscreen mode'
we toggle the drawer to open - the site is now unresponsive (besides the drawer scrolling and any gestures [via AngularJS directives] I've got to hide the drawer)
the drawer toggled when the address bar is visible. Good for usability, but the expected 'fullscreen mode' when using a site doesn't occur (would be nice to have the real estate).
EDIT2: https://medium.com seems to achieve what I'm after.
EDIT3: Some success with a invisible absolute positioned div sitting on top of everything - but that has it's own issues.
Rather than setting overflow: hidden; on body when the drawer is out, how about making the drawer position: fixed; overflow-y: auto;, that way the user can make the choice to scroll the body to get to the address bar or the drawer.
Just out of interest, what does Firefox for Android do in this situation? It might be worth filing a bug with the Chromium team if Firefox doesn't display similar usability problems.
EDIT: I've taken a look at the code at https://github.com/patrickmarabeas/marabeas.io when running in Android Chrome and Android Firefox via their respective ADB-enabled remote debuggers (really good tools!).
I've come to the conclusion that there isn't a nice way to get the address bar to show once it's hidden when body has overflow: hidden on it.
There is however after a hacky way!
Shift the main scrollable area from body to a div, in this case, #content. Then, position: absolute; body and make it fill the viewport plus some extra height when on mobile. Given below is the relevant CSS applied on the mobile browsers:
body {
position: absolute;
top: 0;
bottom: -100px;
left: 0;
right: 0;
}
#content {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow-y: auto;
}
Then, as the browser is looking for body to be doing the scrolling as to whether or not to display the address bar, get the #content scroll to be linked with the main body scroll, though this may not be having an effect!:
var lastScrollTop = 0;
document.getElementById('content').addEventListener('scroll', function(e) {
var currentScrollTop = document.getElementById('content').scrollTop;
if(currentScrollTop < lastScrollTop) {
// Upwards scroll!
document.body.scrollTop -= 10;
} else {
// Downwards scroll!
document.body.scrollTop += 10;
}
lastScrollTop = currentScrollTop;
});
I'm sending you a pull request now: https://github.com/patrickmarabeas/marabeas.io/pull/5
how about using document.body.scrollTop -= 1? I don't hava a try, just a guess

Detect the presence of the ie10 metro address bar with javascript

I have a site that has some call to action buttons in a div that is fixed to the bottom of the screen.
We are currently using a div that is positioned absolutely as follows
<div id="buttonBar">footer code</div>
<style>#buttonBar{ bottom: 0; width: 100%; position: fixed; }</style>
This has worked well in all the browsers except for IE10 in metro (modern) mode.
When a link is clicked the address bar shows and covers the button bar, it then disappears
Other than redesigning the layout of the page, I would like the button bar to sit just above the address bar when it is shown.
Does anyone know a way of detecting whether the address bar is visible using javaScript?
You could try to move the footer above the location-bar, until the location-bar collapses, then drop the footer back down. Here's a potential solution:
1.
Move your footer up 50px (or whatever) if the user is likely on an IE10 touch-enabled browser
if (!!window.navigator.msPointerEnabled) { // sniff for IE10 + touch
$("#buttonBar").css("transform", "translateY(-50px)");
}
2.
Listen for the first interaction with the browser, then collapse the footer with the location-bar.
$("body").on("MSGestureStart MSInertiaStart MSGestureTap MSPointerDown", function () {
$("body").off("MSGestureStart MSInertiaStart MSGestureTap MSPointerDown");
$("#buttonBar").css("transform","translateY(0)");
});
This solution hasn't been 100% reliable, there are clearly some interactions that collapse the location-bar but don't trigger an event. I'm working on a better solution and will update once found, but figured I'd share this to get the ball rolling.

Categories