JQuery mobile footers are not properly fixed to the bottom of the screen. In the normal behavior they follow the bottom with a lag. And in most case it remains quite buggy (it doesn't show at the bottom of the screen).
My question is why is this?
Take into consideration that:
Solutions seems to work quite well for modern browser and CSS (position: absolute,
bottom: 0px). I guess that some navigators don't support that? Which ones? And why is
that?
Sencha touch seems to give a much better alternative on the footer case. But what's the secret? Is it compatible with all browsers?
Jquery is at its .rc1 at the time of this question. It probably won't be fixed in the JQuery mobile 1.0 release. (jQuery Mobile and a fixed footer)
From the release notes:
http://jquerymobile.com/blog/
iOS5: Dramatically improved page transitions and true fixed toolbars
The team has spent a ton of time working on trying to improve
transitions and fixed toolbars because we know these are important
features to developers. After spending hundreds of hours working on
refinements, we now believe that the path to substantial,
cross-platform improvements in these areas can only happen when mobile
platforms start supporting overflow properties natively.
JavaScript-based momentum scroller scripts are too heavy, unresponsive
and narrowly compatible to be a way forward.
That’s why we’re very excited by iOS5′s upcoming support for a
touch-targeted version of overflow:auto , and proper support for
position:fixed which allows for internal scrolling regions with the
native momentum scrolling with CSS. In Beta 3, we’ve added an
enhancement layer to leverages these new CSS capabilities to will
enable us to bring both truly “fixed” toolbars and super smooth
transitions in iOS5, all by using web standards and very little
additional code.
https://github.com/jquery/jquery-mobile/commit/2369e2fa322e721c687408f790230efe4f621fef
https://github.com/jquery/jquery-mobile/commit/2a6c7fc1b982c4308a0450a308f5a66a10e949cf#diff-8
https://github.com/jquery/jquery-mobile/commit/23e79fb1dbba9f4eb15e29b4842579bdd0d1b100
There are some JavaScript scrollable-content plugins that you can use to create a fixed footer that doesn't suck:
iScroll -> http://cubiq.org/iscroll-4
ScrollView -> http://jquerymobile.com/test/experiments/scrollview/
Flexcroll -> http://www.hesido.com/web.php?page=customscrollbar
I'm sure there are more but these are three I've had some success with. I've settled on using iScroll personally.
To get a nice fixed footer you can set the header to position: absolute and top: 0, set the footer to position: absolute and bottom: 0, and then set the content area to position: absolute, top: <bottom of header> and bottom: <top of footer>.
One issue I have found with this is that setting the document to 100% height will not allow the address bar to be scrolled out of view. To fix this, when the load event fires on the window object I set the height of the document to 100px more than the screen height (window.innerHeight). I then scroll to the top of the page ($.mobile.silentScroll(0)), and set a timeout to reset the height of the document to 100%.
$(window).bind('load', function () {
$.mobile.activePage.css({
height : (window.innerHeight + 100) + 'px',
'min-height' : (window.innerHeight + 100) + 'px'
}).find('[data-role="footer"]').css({
bottom : '100px'
});
$.mobile.silentScroll(0);
setTimeout(function () {
$.mobile.activePage.css({
height : '100%',
'min-height' : '100%'
}).find('[data-role="footer"]').css({
bottom : '0px'
});
if ($.mobile.activePage[0].id in myScroll) {
myScroll[$.mobile.activePage[0].id].refresh();
}
}, 750);
});
The above example:
Changes the height of the current pseudo-page to 100px more than the height of the screen.
Changes the position of the footer so it stays in view for the whole process.
Scrolls to the top of the page (i.e. scrolls the address bar out of view).
Sets a timeout to re-size the current pseudo-page to 100% height and reset the position of the footer. The timeout is necessary so the scroll can occur before the height is reset to 100%.
I used iScroll in this code and saved each iScroll instance in an array so that I could refresh the iScroll content area whenever I made changes to the DOM that affected the size of the scrollable area.
I also trigger the load event on the window object whenever there is an orientation change:
$(window).bind('orientationchange', function () {
$(window).trigger('load');
});
I'm working with Jquery.Mobile 1.2alpha, doesn't seem to be an issue anymore. The data-position-'fixed' works great
<footer data-role="footer" data-position="fixed">
<div data-role="navbar">
<ul>
<li>Url 1</li>
<li>Url 2</li>
<li>Url 3</li>
<li>Url 4</li>
</ul>
</div>
</footer>
Additional suggestion to disable the "webview bounce" if you're developing for a wrapper app.
http://community.phonegap.com/nitobi/topics/uiwebview_bounce
Fixed footer solution that worked for me:
<div data-role="footer" data-position="fixed" style="position: absolute">
Related
I currently have a full screen hero image slideshow on the homepage of a site. I have an javascript effect which gets the scroll position and divides it by 1.5 then sets the image transformY position causing a parallex effect.
Here is the code I currently have:
$(window).on("load scroll resize", function () {
$("form:not(.blive_PageEdit) .hero-img .blive_Control img").css({ "margin-top": $(window).scrollTop() / 1.5 });
});
This works as I want, but I have noticed that performance is a major issue expecially on browsers which support asynchronous scrolling which causes a juddering effect.
What I want to know is if there is a better way to implement this? What would be perfect would be to have something like the following but I don't think this is possible with just CSS:
img {
transformY(calc(scrollTop / 1.5));
}
I have also looked at IntersectionObserver, but I am unsure this would achieve what I want to do.
Any thoughts would be helpful. Thanks
first of all I want to say that it's not about content jumping!
I have a navbar and a sidebar which both have absolute position. after user scrolls 100 pixels I change both of them to fixed. but an odd action happens (not always!). wrappers of navbar and sidebar flush for a second. I tested it with different browsers and it does not depend on browser. I tried to reproduce the situation in this fiddle:
https://jsfiddle.net/addxmkgj/
(resize the screen as large as possible it happens in large screens)
-- Edit --
https://codepen.io/anon/pen/dJKBPe
codepen link added too.
Causes
Scrolling can generate scroll events quickly and handlers may need to either throttle scroll events to some extent (e.g. perform code action after scrolling has stopped) or be fairly lightweight functions that can execute quickly.
In addition scroll event handling is not synchronized with page update: if the mouse wheel initiates downward scrolling, scrolling can continue after the wheel is released (and similarly with touch event scrolling). The browser can scroll below a top position of 100px before scroll event handling has had a chance to catch up and change the positioning.
The result is the header jumps down from being partially off-screen to occupy a fixed position at top of screen. The faster the scroll action (or the busier the browser is) the more likely it is that jumping will be noticeable.
A secondary effect in desktop browsing is that when the side bar panel scrolls upwards past top of screen and moves down again, a visible patch of white screen "flashes" momentarily below the side bar before fixed positioning takes effect.
Experimental Remedies
Flashing of the side bar can be reduced but not necessarily fully eliminated, by increasing the height of the container. Changing the height to 150% with visible overflow met with some success:
.side-bar {
position: absolute;
height: 150%;
... /* more declarations */
This may or may not conflict with application requirements.
Some mitigation of navbar jumping can be achieved by using requestAnimationFrame call backs to monitor scrollTop values and change positioning as necessary. This does not use scroll event handling as such:
$(document).ready(function() {
$(window).resize(function() {
if( $(window).width() > 850) {
$('.navbar').css('display', 'block');
} else {
$('.navbar').css('display', 'none');
}
});
scrollTo(0, 0);
var num = 100;
var bAbsolute = true;
function checkScroll() {
var newTop = $(window).scrollTop();
if( bAbsolute && newTop >= num) {
$('.navbar').css('position', 'fixed');
$('.navbar').css('top', '0');
$('.side-bar').css('position', 'fixed');
$('.side-bar').css('top', '0');
bAbsolute = false;
}
if( !bAbsolute && newTop < num) {
$('.navbar').css('position', 'absolute');
$('.side-bar').css('position', 'absolute');
$('.navbar').css('top', '100px');
$('.side-bar').css('top', '100px');
bAbsolute = true;
}
requestAnimationFrame( checkScroll);
}
requestAnimationFrame( checkScroll)
});
This code showed an improvement in jump reduction but was not perfect. It is not particularly a JQuery solution and calls requestAnimationFrame directly.
One option, of course, is to do nothing given browser timing constraints.
Update
This MDN guide for Scroll linked effects explains the root cause problem better than I was able to:
most browsers now support some sort of asynchronous scrolling .... the visual scroll position is updated in the compositor thread and is visible to the user before the scroll event is updated in the DOM and fired on the main thread ... This can cause the effect to be laggy, janky, or jittery — in short, something we want to avoid.
So the absolutely positioned elements can scroll off screen (to some extent) before scroll handlers are notified of a new scroll position.
The solution going forward is to use sticky positioning (see the scroll effects guide above or the CSS position guide. However position:sticky swaps between relative and fixed position so the HTML would need redesigning to accommodate this.
Sticky positioning is also leading edge technology at January 2018, and not yet recommended for production use on MDN. A web search for "JQuery support sticky position" revealed a choice of JQuery plugin support.
Recommendation
Potentially the best-case compromise may be to redesign the HTML to use sticky positioning and include a JQuery plugin that uses native support when available or a polyfill when not - site visitors with supporting browsers will get the best experience, those with older browsers will get functional support.
On some of our pages, we've got some legacy JQuery that detects when a page is scrolling and then sets the height of the main element, to position the footer correctly on both mobile and desktop:
function scrollPage(event){
base.keepMainMarginOverFooter();
// other functions
}
$(window).on('scroll',scrollPage);
This is the offending function:
keepMainMarginOverFooter:function() {
// Adjusts container height so footer is clickable but can also be revealed on mobile
var h = 0;
$('.fp-section.visible').children().each(function() {
h+= $(this).outerHeight()
});
$('#main').css({ height: h });
}
And it seems that there's a bug in Chrome (Version 61.0.3163.100) that seems to trigger if you're actively scrolling during any event which triggers the above code (we also have some JQuery functions that , which automatically takes you to the end of the #main section, ie the bottom of the page. Or at least I guess it's a bug - this doesn't seem to happen in Safari (Version 11.0 12604.1.38.1.7), and it doesn't happen if you wait a couple of seconds after page load before scrolling.
It's tempting to remove this function for something simpler, but it's in the middle of enough dependencies that that wouldn't be trivial.
Is this a known issue with a decent workaround?
I'm currently developing a website that that has a fixed banner div that is centered, and I'm using the jQuery below to ensure that it scrolls correctly even though it is a fixed positioned div.
jQuery:
$(window).scroll(function() {
$('#top-content').css('left', -$(this).scrollLeft() + "px");
});
However, I have come across an issue within IE(version 9). The issue is that when the user scrolls the website (creating a minus left margin on the "top-content" div, to give the effect of scrolling) and then if they maximize the webpage, the left margin is still present causing the div to not be centered.
I have attempted to remedy this with the jQuery below, but as of yet no luck
$(window).resize(function() {
if ($("#top-content").width() < $(window).width()) {
$('#top-content').css('left:0px');
}
});
Any ideas?
You better do
$('#top-content').css('left', '0px');
In your resize event.
I just upgraded from cordova 3.0 to 3.1 and I'm still experiencing a very disturbing issue (which still exists when playing with KeyboardShrinksView preference).
Whenever I'm focusing an element (input/textarea) which triggers the keyboard opening, the element gets hidden behind the keyboard and I need to scroll down (using webkit-overflow-scrolling for scrolling by the way) in order to see the element and its content.
When KeyboardShrinksView is set to true the page won't even scroll, making it even worse.
Any solutions in order to fix this issue? I've seen a few questions and bug reports but with no working solutions (or solutions at all).
Playing with the "fullscreen" preference won't solve the problem.
Just had a very similar problem to this. Some of the hacks found on this site did work, but had nasty side effects (such as making a mess of scrolling or CSS layout). Finally came up with a brand new stupid hack.
Viewport meta tag:
<meta name="viewport" content="initial-scale=1, maximum-scale=1, width=device-width" />
JavaScript run after load:
document.body.style.height = screen.availHeight + 'px';
And that's it. Works on iOS 7 and I have no idea why.
Finally fixed the problem with the help of the following plugin: jQuery scrollTo plugin
Whenever i'm focusing on an element i'm triggering a focus event which does the following calculations and updates the scroll position:
updateScroll: function(e){
var el = $(e.currentTarget);
var offset = -$(".scrollerWrap").height() + $(el).height();
$(".scrollerWrap").scrollTo(el,{offset: offset});
}
Sticks the bottom of the input/textarea to the top of the keyboard. Works like a charm, even if the solution needs to go through that bit of JavaScript.
Well, logically the view should move up when the keyboard opens. I have faced a similar issue with iOS7 and to fix it I have applied few css tweaks.
Tweaks were applied on the wrapper class/id which is containing the content of the app.
position: relative;
overflow: hidden;
height: 460px;
width: 320px;
Note - Height and width are judged dynamically depending on the device height and width
height = window.innerHeight
width = window.innerWidth
By using jQuery selectors height and width are appended to wrapping class/id.
Works for me.
document.body.style.height = (screen.availHeight - 100) + 'px';
I think the issue here originates from Framework7.
document.body.style.height = window.outerHeight + 'px';
The above code placed in my index.js file worked like charm.