iOS7 on "touchmove", prevent fixed element going negative? - javascript

I have a fixed row of indicators (slider-indicators) that when it reaches the bottom bound, it should sit on top of the footer. On the desktop everything works fine, and I know that on iOS the scrolling freezes the DOM manipulation.
So I tried using on('touchmove') event, which does a decent job, but when the user scrolls up the page on iOS, moving the website itself up (and revealing the blank/grey/ background), the fixed element moves with it also.
I'm try to disable this feature, and usually works with removing the touch event off('touch'), but how would I rebind it again, so that the DOM manipulation works as the user scrolls?
This is what code I have:
$(window).on('touchmove',moveIndicators);
$(window).scroll(moveIndicators);
function moveIndicators() {
var d = $(document).height(),
w = $(window).height(),
s = $(this).scrollTop(),
bottomBound = (navigator.userAgent.match(/(iPhone);.*CPU.*OS 7_\d/i)) ? 119 : 50;
$location = $('.location-nav');
if(d - (w + s) <= bottomBound) {
$location.css({ bottom: bottomBound - (d - (w + s)), 'margin-bottom': '0px' });
} else {
$location.css({ bottom: 0, 'margin-bottom': '0px' });
}
}

Related

DOM element position slow while scrolling + difference between scrollbar-scrolling and mouse/touchpad-scrolling

I'm having a little problem with Safari - When i want to update a DOM element's position on scroll event, Safari seems not to catch up with the changes (resulting in a jumpy lag effect).
I checked it on other browsers (Chrome, FF, IE8+) and this seems to be specific to Safari.
I made a jsfiddle to illustrate my problem:
$("#container").on("scroll", function() {
$("#slide").css({
left: $("#container").scrollLeft() + "px"
});
var leftPos = 0;
for(var i = 0; i < 2000 ; i++) {
leftPos = $("#slide").css("left");
}
$("#info").text(leftPos);
});
http://jsfiddle.net/a4b86et3/2/
As you can see, I added an additional loop of DOM reading on each scroll to simulate "more operations going on" on each event occurrence, as this mechanism is a part of a bigger project, which contains many other DOM operations. (Notice, that this example works smooth everywhere except Safari)
Also, i used jQuery just for the convenience, the actual project uses pure js.
I managed to partially fixed the issue
by changing the left = x property to transform = translate3d(x,0,0), so the browser would use the GPU.
$("#container").on("scroll", function() {
$("#slide").css({
'-webkit-transform': 'translate3d(' + $("#container").scrollLeft() + 'px, 0, 0)'
});
var leftPos = 0;
for(var i = 0; i < 1900 ; i++) {
leftPos = $("#slide").css("left");
}
$("#info").text(leftPos);
});
http://jsfiddle.net/a4b86et3/3/
However, sometimes I'm still experiencing a slight lag/glitching while scrolling.
But, what's more important, this fix doesn't affect the scrolling, when I'm using a mouse scroll or touchpad! While dragging the scrollbar works way better, using any of the above brings me back to my initial problem.
Any ideas why this happens and how to fix it?
tl;dr; - Safari is slow when changing element position on scroll; translate3d seems to not work properly when using mouse scroll/touchpad.
I had the exact same issue, and it took me some time to figure out the fix. Here is an updated jsfiddle showing you how to resolve the issue in Safari: http://jsfiddle.net/a4b86et3/4/
function handle_scroll() {
$("#slide").css({
'-webkit-transform': 'translate3d(' + $("#container").scrollLeft() + 'px, 0, 0)'
});
var leftPos = 0;
for(var i = 0; i < 1900 ; i++) {
leftPos = $("#slide").css("left");
}
$("#info").text(leftPos);
}
$("#container").on("scroll", handle_scroll);
$("#container").on('mousewheel', function(e) {
e.preventDefault()
var maxX = this.scrollWidth - this.offsetWidth
var maxY = this.scrollHeight - this.offsetHeight
this.scrollTop = Math.max(0, Math.min(maxY, this.scrollTop - e.originalEvent.wheelDeltaY))
this.scrollLeft = Math.max(0, Math.min(maxX, this.scrollLeft + e.originalEvent.wheelDeltaX))
handle_scroll(e)
})
In brief: if you handle the mousewheel event yourself, calculate the correct scroll values there, and then call your handler code, things start working.
I'm not sure why Safari makes you jump through this hoop, but luckily the fix isn't too involved.
Hope this helps.

scroll speed with mousewheel jquery plugin

I want to imitate the Google+ header with the search bar. When you scroll down it goes to top:-60px and the second horizontal menu will be top:0 from top:60px and become the main top horizontal menu, while the one with top:-60px remains hidden until we scroll to top.
I managed to do this, but it only works when I scroll slowly (with trackpad, OSX, Chrome33). I researched and found out the scroll speed depends on the hardware (touchpad, mouse), the OS and even on the browser. I found mousewheel plugin, that aims to make the scrolling speed equal but I can't make it work.
Here is the js code: ( The delta divisions I got from here: https://stackoverflow.com/a/16696129 )
<script type="text/javascript">
gn_top_menu_featured = $('.gn-top-menu-featured'),
gn_top_menu = $('.gn-top-menu'),
hide_gn_top_menu_featured = 0,
gn_top_menu_position = 44;
$('body').on('mousewheel', function(event) {
if( event.deltaX >= 40 )
event.deltaX /= 40;
if( event.deltaY >= 40 )
event.deltaY /= 40;
var sy = $('body').scrollTop();
if ( sy >= hide_gn_top_menu_featured && sy <= gn_top_menu_position ) {
gn_top_menu_featured.css('top', -sy);
gn_top_menu.css('top', gn_top_menu_position-sy);
}
else {
// whatever
}
});
</script>
I really want to get this working properly, thank in advance. :)
Turns out i misunderstood your problem at first. Here's another attempt at solving this. I still might not be understanding you correctly, because I still don't need to control the mousewheel speed to make this work. Here's the updated fiddle.
I use the $(window).scroll event to check the $(window).scrollTop() value and change the css class of the div.
$(window).scroll(function(){
$("#nav").css("top", ($(window).scrollTop() < 60 ? (60 - $(window).scrollTop()) : 0) + 'px');
if ($(window).scrollTop() > 60) {
$("#nav").addClass('sub-60').text('WOOT!');
}
else {
$("#nav").removeClass('sub-60').text('MAIN NAV');
}
});

Prevent scrolling when done too quickly with jQuery

In order to prevent mousewheel scrolling to scroll the entire page when reaching the top/bottom of an element with its own scrollbars, I'm using Brandon Aaron's Mousewheel plugin.
This works fine, as long as I don't scroll too quickly. It seems that when scrolling really quickly, two events will pass the "I haven't reached the top/bottom" check yet and will both be executed. However, one of them will then scroll the element to the top/bottom and the next one will then scroll the entire page, which was what I was trying to prevent.
I'm currently doing this
$('.popupContents').bind('mousewheel', function (e, d) {
var t = $(this);
if (d > 0 && t.scrollTop() === 0) {
e.preventDefault();
} else if (d < 0 && (t.scrollTop() == t.get(0).scrollHeight - t.innerHeight())) {
e.preventDefault();
}
});
(As posted in Prevent scrolling of parent element? )
How do I make it so that the function properly stops all events at the top/bottom even when the user scrolls quickly?
I ended up manually tracking the desired scroll position and disallowing the normal scroll event altogether.
var wantedScrollTop = 0;
$('.popupBody').bind('mousewheel', function (e, d) {
var t = $(this);
var scrollTo;
if (d > 0) {
scrollTo = Math.max(0, wantedScrollTop - 30);
} else if (d < 0) {
scrollTo = Math.min(t.get(0).scrollHeight - t.innerHeight(), wantedScrollTop + 30);
}
if (typeof scrollTo !== "undefined") {
wantedScrollTop = scrollTo;
t.scrollTop(wantedScrollTop);
//t.stop().animate({ scrollTop: wantedScrollTop + 'px' }, 150);
}
e.preventDefault();
});
d is the scroll direction, so I'm manually keeping track of the wanted scroll position here. In my case there is only one popup at a time, so I didn't bother sticking the wantedScrollTop in a data- attribute or something similar on the element, which could be useful when youdo have multiple elements that need to track their own scroll position.
It is not doing a fluent scroll like your browser would, but it will change the vertical scroll position by 30 pixels for each time the scrollwheel triggers the event. I left the commented out line in the code to show how that could be achieved. However, for me this resulted in scrolling which feeled very lagged when scrolling quickly.

jQuery scroll page so cursor stays at the "logical center"

i have a huge html form , with near 350 controls that take 5-6 times of the user screen height.
user starts completing each input field from the beginning of the page and goes on.
once the cursor rich near the bottom of screen user must be able to see some next input fields so here is the problem :
i want to avoid the scrollbar usage.
i want to set some "margines" ( say 200px for each page side )
if user clicks a control that is near the screen edge, here this mechanism must work also
i'm looking for a jQuery solution
playing around with jQuery.ScrollTo, but can't figure out how to embed my logic into code.
This should do it
http://jsfiddle.net/JsWnk/
$(document).ready(function() {
$('input').focus(function() {
var padding = 100; // Desired page "padding"
var lbound = $(this).offset().top - $(window).height() + padding;
var ubound = $(this).offset().top - padding;
if ($(window).scrollTop() < lbound)
$(window).scrollTop(lbound);
else if ($(window).scrollTop() > ubound)
$(window).scrollTop(ubound);
});
});
​
Something like this should work...
http://jsfiddle.net/q9QHQ/
$(document).ready(function() {
$('input').focus(function() {
if ($(this).offset().top > 100)
$(window).scrollTop($(this).offset().top + 100);
});
});

Jquery - Choppy animations in IE scrolling

So I have a toolbar that is on the left side of my page that I have animating when the user scrolls to stay focused on the top of the page. It works perfectly in every browser except IE. In IE, it appears to almost do it twice. It bounces around and is very strange. This is my code.
$(window).scroll(function () {
var windowScrollPosition = $(window).scrollTop(),
toolbarLocation = toolbar.offset().top + toolbar.height(),
canvasSize = formCanvas.offset().top + formCanvas.height();
//Give toolbar a new position relative to container
if ((toolbarLocation + windowScrollPosition) < canvasSize + toolbarLocation) {
toolbar.animate({'margin-top': (windowScrollPosition - 95) <= 0 ? windowScrollPosition : (windowScrollPosition - 95) + 'px'}, 65);
}
});
any thoughts on how to fix this in IE? Thanks!
Unless you want it to animate, i would use position: fixed to keep it there instead of animating it. That would probably fix your problem at least.

Categories