I am answering this question because it is the original one posted about this topic, and states clearly that the issue here is a noticeable flicker by using window.scrollTo()
, jQuery's scrollTop()
or the controversial $.mobile.silentScroll()
from the JQM library (timeout + scroll).
I have had recently to address exactly the same issue, and that is what I came up:
the great JQM team has done a great job in the past to optimize and speed-up transitions also for low-end mobile devices.
In short, this critical point has been solved by JQM in some way by trying to pair the pages
to a certain value inside the ยง.mobile.silentScroll()
function. I had to remove this function to build my own:
$(document).on("mobileinit", function () {
// other settings...
$.mobile.SerialTransition.prototype.scrollPage = $.noop;
$.mobile.ConcurrentTransition.prototype.scrollPage = $.noop;
});
As I have two kind of pages, the first one where I need to remember the scroll position (list page), and a second one (card page) where I need to start always from the top, I will store this information inside a custom data-attribute
.
Here is for instance this setting for the three pages in my example below:
<div id="page-one" data-role="page" data-transition-scroll="keep-position">
<div id="page-two" data-role="page" data-transition-scroll="top-position">
<div id="page-three" data-role="page" data-transition-scroll="keep-position">
As pointed out in the question, I have had also to offset the page
from the top, and this is the whole code:
var scrollHandler = {
setScrollData: function (prevPage, toPage) {
if(typeof toPage == "object" && typeof prevPage == "object") {
$(prevPage).data("scroll-top", $(window).scrollTop());
}
},
resetContent: function (toPage) {
var scrollMode = $(toPage).data("transition-scroll");
if(scrollMode === "top-position") {
var content = $(toPage).find(".ui-content")[0];
var contentStyle = $(content).attr("style"); /* Force reflow */
$(content).css({"top": "0px"});
}
},
freezeContent: function (prevPage) {
var scrollTop = $(prevPage).data("scroll-top"),
content = $(prevPage).find(".ui-content")[0],
fixedHeader = $(prevPage).find(".ui-header-fixed")[0],
headerBottom = $(fixedHeader).outerHeight() - fixedHeader.offsetTop;
$(content).css({"top": -scrollTop + "px"});
window.scrollTo(0,0);
},
unFreezeContent: function (toPage) {
var scrollTop = $(toPage).data("scroll-top"),
scrollMode = $(toPage).data("transition-scroll"),
content = $(toPage).find(".ui-content")[0],
contentStyle = $(content).attr("style"); /* Force reflow */
$(content).removeAttr("style");
window.scrollTo(0, scrollMode ==="top-position" ? 0 : scrollTop);
}
};
The JQM pageevents
used here are are the following:
$(document).on("pagecontainerbeforehide", function(e, ui) {
scrollHandler.freezeContent(ui.prevPage);
});
$(document).on("pagecontainerbeforechange", function(e, ui) {
scrollHandler.setScrollData(ui.prevPage, ui.toPage);
});
$(document).on("pagecontainerbeforeshow", function(e, ui) {
scrollHandler.resetContent(ui.toPage);
});
$(document).on("pagecontainershow", function(e, ui) {
scrollHandler.unFreezeContent(ui.toPage);
});
Lastly, there is also a little bit of CSS:
/* large desktop screen */
.ui-header,
.ui-content,
.ui-footer {
max-width: 870px;
margin: auto;
}
/* needed for the scrollhandler */
.ui-content {
position: relative;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
Additional note
For external pages and for pages which aren't dom-cached, there would be the need for a custom page history because:
- in my example the scroll value is stored inside the page itself and
- the current standard JQM page history implementation it would not be enough for this purpose
Here is an example:
The slide
transition was slowed down on purpose to examine the result:
