Reputation: 2744
I want my fixed header element to slide up off the screen (effectively hide) when the user scrolls down, and move back down when the user scrolls up.
The actual animation and logic is working properly, but the animation doesn't begin until the user stops scrolling, as opposed to beginning while the scrolling is still going like it should.
This is replicated on Chrome and Firefox. However, with the exact same code, the solution seems to work properly in a JSFiddle:
https://jsfiddle.net/8cj7v6n5/
var lastScroll = 0;
var scrollDelta = 10;
var animating = false;
$(window).on('scroll', function() {
//if animation isn't currently taking place, begin animation
if (!animating) hasScrolled();
});
function hasScrolled() {
var st = $(window).scrollTop();
//if user hasn't scrolled past scrollDelta, do not animate yet
if(Math.abs(lastScroll - st) <= scrollDelta)
return;
animating = true;
if (st > lastScroll && st >= 0){ // Scroll Down
$('header').animate( { top: -80 }, { queue: false, duration: 500, complete: function() { animating = false; } });
}
else { // Scroll Up
$('header').animate( { top: 0 }, { queue: false, duration: 500, complete: function() { animating = false } });
}
lastScroll = st;
}
Upvotes: 2
Views: 1013
Reputation:
The problem is the value you use for the lastscroll is only updated when the animation happens. It should be updated always because you can scroll the screen while the animation is running and the lastscroll value will be different than the real top scroll value, then you compare the values again and the system thinks is is higher or lower than it really is.
Example:
This is the corrected code:
var lastScroll = 0;
var scrollDelta = 10;
var animating = false;
$(window).on('scroll', function() {
//if animation isn't currently taking place, begin animation
if (!animating) {hasScrolled()}else{lastScroll = $(window).scrollTop();};
});
function hasScrolled() {
var st = $(window).scrollTop();
//if user hasn't scrolled past scrollDelta, do not animate yet
if(Math.abs(lastScroll - st) <= scrollDelta)
return;
animating = true;
if (st > lastScroll && st >= 0){ // Scroll Down
$('header').animate( { top: -80 }, { queue: false, duration: 500, complete: function() { animating = false; } });
}
else { // Scroll Up
$('header').animate( { top: 0 }, { queue: false, duration: 500, complete: function() { animating = false } });
}
lastScroll = st;
}
This is the fiddle I used to debug with the console logs: https://jsfiddle.net/8cj7v6n5/18/
Edit: This code works for me outside fiddle, try it if it works then the problem is in another component of the page not published here. Maybe it is another line of code or library overriding the behavior of .animate() or the scroll event.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
var lastScroll = 0;
var scrollDelta = 10;
var animating = false;
var lastScroll = 0;
var scrollDelta = 10;
var animating = false;
$(window).on('scroll', function() {
//if animation isn't currently taking place, begin animation
if (!animating) {hasScrolled()}else{lastScroll = $(window).scrollTop();};
});
function hasScrolled() {
var st = $(window).scrollTop();
//if user hasn't scrolled past scrollDelta, do not animate yet
if(Math.abs(lastScroll - st) <= scrollDelta)
return;
animating = true;
if (st > lastScroll && st >= 0){ // Scroll Down
$('header').animate( { top: -80 }, { queue: false, duration: 500, complete: function() { animating = false; } });
}
else { // Scroll Up
$('header').animate( { top: 0 }, { queue: false, duration: 500, complete: function() { animating = false } });
}
lastScroll = st;
}
</script>
<style type="text/css">
body {
height: 2000px;
width: 100%;
background-image: url(http://static.tumblr.com/cc2l8yc/qa8nbkd68/2.jpg);
background-repeat: repeat;
}
header {
height: 80px;
width: 100%;
background-color: red;
position: fixed;
top: 0;
left: 0;
}
</style>
</head>
<body>
<header></header>
</body>
</html>
Upvotes: 1
Reputation: 2114
Instead of using animating flag, you can just queue the animations and use stop() with animate() to run the last animation in queue.
EDIT: you can use the flag for direction to detect if there is change in direction of scrolling.
JavaScript:
var lastScroll = 0;
var scrollDelta = 10;
var animationDirection = 0; // 0 for up direction, 1 for down direction
$(window).on('scroll', function () {
hasScrolled();
});
function hasScrolled() {
var st = $(window).scrollTop();
if (Math.abs(lastScroll - st) <= scrollDelta)
return;
if (st > lastScroll && st >= 0 && animationDirection == 0) { // Scroll Down
$('header').stop().animate({ top: -80 }, 500);
animationDirection = 1;
}
else if (st <= lastScroll && st >= 0 && animationDirection == 1) { // Scroll Up
animationDirection = 0;
$('header').stop().animate({ top: 0 }, 500);
}
lastScroll = st;
}
JSFiddle: https://jsfiddle.net/8cj7v6n5/27/
Upvotes: 2