Reputation: 2615
What's the best way to animate the position of a div on scroll position? Essentially, when you reach a certain point on the page... a fixed element will animate up.
I have included below what I currently have... but it's a little slow and seems to slide up... slowly... half way... then complete. Any thoughts?
var shareHeight = $('.related-share-container').height();
$('.related-share-container').css('bottom',-shareHeight);
$(window).scroll(function() {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 150) {
$('.related-share-container').stop().animate({ bottom: 0 }, 500);
} else {
$('.related-share-container').stop().animate({ bottom: -shareHeight }, 500);
}
});
UPDATE FOR REWARD
This is the dev site I am working on: http://goo.gl/KcFdE6 and as you can see, if you scroll to the bottom and stop, it slides up fairly well, BUT, if you keep scrolling... it's interacting with the animation and you can a really jumpy/slow transition. Any ideas?
Upvotes: 3
Views: 12953
Reputation: 4199
It is happening cause for each scroll movement previous animation get stopped and new begins, which is slower than previous one cause it has less distance to animate. Thus you need some flag in your code to prevent same animation triggering again and again.
Modified JS:
Here I am using done
class as a flag.
var shareHeight = $('.related-share-container').height();
$('.related-share-container').css('bottom',-shareHeight);
$(window).scroll(function() {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 150) {
if(!$('.related-share-container').hasClass('done'))
$('.related-share-container').addClass('done').stop().animate({ bottom: 0 }, 500);
} else {
if($('.related-share-container').hasClass('done'))
$('.related-share-container').removeClass('done').stop().animate({ bottom: -shareHeight }, 500);
}
});
Upvotes: 5
Reputation: 43156
I'd use css transitions instead of jquery animate
as follows, so that you don't have to worry about the animation queue.
(Using css, You could even make use of hardware acceleration)
css
.element-to-animate {
/*your style rules*/
transform: translate3d(0, 0, 0);
transition:height .5s linear;
}
.hide {
height:0 !important;
}
script:
var sliderTop = $(window).height() - 150;
$(window).scroll(function () {
var scrollTop = $(window).scrollTop();
if (scrollTop > sliderTop) {
if ($('.overlay').hasClass('hide'))
$('.overlay').removeClass('hide');
} else {
if (!$('.overlay').hasClass('hide'))
$('.overlay').addClass('hide');
}
});
Upvotes: -1
Reputation: 1493
You have 2 options, both of which are good, but the latter is better:
A. Use a debounced function - in other words, you want to throttle the scroll listener so that it only happens once out of every X milliseconds, so if someone is mid-scroll, it won't happen.
Libraries such as lodash provide this as _.debounce(fn, time);
If you don't use a library, this can be achieved like this (I'm using the code from your current site):
var shareHeight = $('.related-share-container').height();
$('.related-share-container').css('height',shareHeight);
$('.project-content-container').css('margin-bottom',shareHeight);
$('.related-share-container').css('margin-bottom',-shareHeight - 30);
var timeout,
elem = $(this);
elem.bind('scroll', function() {
clearTimeout(timeout);
timeout = setTimeout(function(){
var y = elem.outerHeight() + api.getContentPositionY() + 600 >= api.getContentHeight();
if (y) {
$('.related-share-container').stop(true).animate({ 'margin-bottom': 0 }, { queue: false, duration: 300 });
} else {
$('.related-share-container').stop(true).animate({ 'margin-bottom': -shareHeight - 30 }, { queue: false, duration: 300 });
}
}, 50); //50ms debounce time
});
B. Animate in steps - in other words, each time your animate function will be called, it will not animate the full size of the container, but will only animate the amount that was scrolled (or a set step size). This is actually a much better solution, since currently, if someone scrolls down and the huge footer pops up, it's almost impossible to scroll back up. Libraries such as tween.js make this easy.
Upvotes: 0
Reputation: 1
First check this demo
CSS
.related-share-container{
position: fixed;
left: 0;
bottom: 0;
width: 100%;
z-index: 9999;
padding: 15px 0;
font-size: 16px;
display:none;
}
download animate.css file and link to your file
JS
$(window).scroll(function(e) {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 150) {
$('.related-share-container').removeClass('rotateOutUpLeft').addClass('animated rotateInUpLeft').show();
} else {
$('.related-share-container').removeClass('rotateInUpLeft').addClass('rotateOutUpLeft');
}
});
Its working perfect. don't forget to download animate.css file and add to your site. you can choose animation effect.
Upvotes: 0
Reputation: 3397
Going off the fact that you mention the iffy animation rather than actual div placement, the problem is that your js code executes every time you scroll, even if you are already animating. This causes you to stop the animation and restart it. This is the cause of the slow and laggy animation effect you are seeing.
What you need to do is keep track of if you are animating and react based on that so the animation has a chance to complete.
//...
var isAnimating = false;
$(this).bind('scroll', function() {
//jQuery does have a :animated selector as well that can handle this
if(!isAnimating){
isAnimating = true;
var y = $(this).outerHeight() + api.getContentPositionY() + 600 >= api.getContentHeight();
if (y) {
$('.related-share-container').animate({ 'margin-bottom': 0 }, { queue: false, duration: 300 }, 'slow', function(){ isAnimating = false; });
} else {
$('.related-share-container').animate({ 'margin-bottom': -shareHeight - 30 }, { queue: false, duration: 300 }, 'slow', function(){ isAnimating = false; });
}
}
});
Warning! Code not tested but is an approximation of needed code You will need to take into account that if they are scrolling up, it is okay to stop the animation and reverse direction.
Upvotes: 0
Reputation: 1076
If I understood you correctly you want an element which is somewhere on the page to scroll once it's on a specific position of the viewport.
Check this fiddle: http://jsfiddle.net/6bZab/11/ JS:
var oldElemBottom;
function isScrolledIntoView(elem) {
var win = $(window),
marginBot = 20,
docViewTop = $(window).scrollTop(),
docViewBottom = docViewTop + $(window).height(),
elemTop = $(elem).offset().top,
elemBottom = elemTop + $(elem).height();
if (typeof oldElemBottom !== 'undefined'){
elemBottom = oldElemBottom;
}
if ((win.scrollTop() + win.height() - marginBot) >= elemBottom){
oldElemBottom = elemBottom;
return true
} else {
return false
};
}
CSS:
#container {
width: 100%;
height: 1000px;
}
#elem {
width:80px;
height:50px;
background:#333;
color:#FFF;
text-align:center;
right: 0;
}
.first{
background-color: green;
height: 1000px;
}
.absolute_pos{
position: absolute;
top: 600px;
}
Element is scrolling as soon as the bottom of the viewport + marginBot passes the element. It's fixed afterwards until it's goin top again.
Upvotes: 0