Can someone tell me why my code isn't working?
var distance = $('#introSection').offset().top,
$window = $(window);
$window.scroll(function() {
if ( $window.scrollTop() >= distance ) {
document.getElementById("hoveredLink").style.left = document.getElementById("introNav").target.offsetLeft + "px";
document.getElementById("hoveredLink").style.left = document.getElementById("introNav").target.offsetWidth + "px";
}
});
I want the "hoveredLink" element to scroll to the menu element "introNav" if the "introSection" reaches the very top of the window :( is not working yet though
Try using it this way it will work.
var distance = 10;
$('body').scroll(function() {
var scroll = $(this).scrollTop();
if ( scroll >= distance ) {
console.log("i am working!");
}
});
Sorry for the terrible title, but I'm not sure how else to describe what I'm trying to build. I'm using some code I found on this site, basically what I'm trying to do is build a left handed navigation menu, that highlights the appropriate section as the user scrolls to it.
$(document).ready(function() {
var topRange = 200, // measure from the top of the viewport to X pixels down
edgeMargin = 20, // margin above the top or margin from the end of the page
animationTime = 600, // time in milliseconds
contentTop = []; //array of sidebar links
$('nav ul').append('<div id="slider"></div>');
var sliderTop = $("nav ul li a").eq(0).parent().position().top;
var sliderLeft = $("nav ul li a").eq(0).parent().position().left;
var sliderHeight = $("nav ul li a").eq(0).parent().outerHeight();
$('#slider').css({
'height': sliderHeight,
'left': sliderLeft,
'top': sliderTop,
'width': '100%'
});
// Stop animated scroll if the user does something
$('html,body').bind('scroll mousedown DOMMouseScroll mousewheel keyup', function(e) {
if (e.which > 0 || e.type == 'mousedown' || e.type == 'mousewheel') {
$('html,body').stop();
}
})
// Set up content an array of locations
$('#sidebar').find('a').each(function() {
contentTop.push($($(this).attr('href')).offset().top);
})
// Animate menu scroll to content
$('#sidebar').find('a').click(function() {
var sel = this,
newTop = Math.min(contentTop[$('#sidebar a').index($(this))], $(document).height() - $(window).height()); // get content top or top position if at the document bottom
$('html,body').stop().animate({
'scrollTop': newTop
}, animationTime, function() {
window.location.hash = $(sel).attr('href');
});
return false;
})
//scroll function
function scroller() {
var winTop = $(window).scrollTop(),
bodyHt = $(document).height(),
vpHt = $(window).height() + edgeMargin; // viewport height + margin
$.each(contentTop, function(i, loc) {
if ((loc > winTop - edgeMargin && (loc < winTop + topRange || (winTop + vpHt) >= bodyHt))) {
//animate slider
x = $("#sidebar li").eq(i).position();
$("#slider").animate({
top: (x.top)
}, 100);
}
})
}
//scroll event handler
$(window).scroll(scroller)
})
I have most of it working, however when you actually click a link on the menu the animation is very slow to catch up with the actual scrolling. I understand why this is happening, because it updates the position one at a time after each section is reached, but I'm wondering if there's a way to make this animation faster, and more fluid. I've attached a fiddle with my code, thank you in advance for your help!
http://jsfiddle.net/jamesmyers/6mbmq1pe/
You will get a better slider animation effect by temporarily detaching the scroll handler and scrolling the slider directly, with the same animationTime as for the main animation.
To do this, you also need to :
namespace the scroll event .nav, to allow safe use of .off()
stop() the slider animation in the "if the user does something" block
I've also included a few efficiency savings in the way contentTop and #slider are set up but these are not actually necessary.
$(document).ready(function() {
var topRange = 200, // measure from the top of the viewport to X pixels down
edgeMargin = 20, // margin above the top or margin from the end of the page
animationTime = 600, // time in milliseconds
contentTop, //array of sidebar links
navLinkWrapper = $("nav ul li a").eq(0).parent();
var $slider = $("<div id=\"slider\" />").css({
'height': navLinkWrapper.outerHeight(),
'left': navLinkWrapper.position().left,
'top': navLinkWrapper.position().top,
'width': '100%'
}).appendTo($('nav ul'));
// Stop animated scroll if the user does something
$('html,body').on('scroll mousedown DOMMouseScroll mousewheel keyup', function(e) {
if (e.which > 0 || e.type == 'mousedown' || e.type == 'mousewheel') {
$('html,body').stop();
$slider.stop(); //<<<<<<<
}
});
// Set up content an array of locations
contentTop = $('#sidebar a').map(function() {
return $($(this).attr('href')).offset().top;
});
// Animate menu scroll to content
$('#sidebar a').on('click', function(e) {
e.preventDefault();
$(window).off('scroll.nav', scroller); //<<<<<<<
$slider.stop().animate({ //<<<<<<<
top: ($(this).closest("li").position().top) //<<<<<<<
}, animationTime); //<<<<<<<
var sel = this,
newTop = Math.min(contentTop[$('#sidebar a').index($(this))], $(document).height() - $(window).height()); // get content top or top position if at the document bottom
$('html,body').stop().animate({
'scrollTop': newTop
}, animationTime, function() {
window.location.hash = $(sel).attr('href');
$(window).on('scroll.nav', scroller); //<<<<<<<
});
});
//scroll function
function scroller() {
var winTop = $(window).scrollTop(),
bodyHt = $(document).height(),
vpHt = $(window).height() + edgeMargin; // viewport height + margin
$.each(contentTop, function(i, loc) {
if ((loc > winTop - edgeMargin && (loc < winTop + topRange || (winTop + vpHt) >= bodyHt))) {
//animate slider
$slider.animate({
top: ($("#sidebar li").eq(i).position().top)
}, 100);
}
});
}
//scroll event handler
$(window).on('scroll.nav', scroller); //<<<<<<<
});
Updated fiddle
I'm building a website. http://check.topicwine.com
Have a look to see my work.
I want to make a static sidebar. I'm using the code:
$(function() {
var offset = $("#ad-wrapper").offset();
var topPadding = 60;
$(window).scroll(function() {
if ($(window).scrollTop() > offset.top) {
$("#ad-wrapper").stop().animate({
marginTop: $(window).scrollTop() - offset.top + topPadding
});
} else {
$("#ad-wrapper").stop().animate({
marginTop: 0
});
};
});
});
The sidebar comes along, but it also goes where it shouldn't. I mean, it enters the footer as well. Rather, it overlaps the footer.
I want it to stop next to the grid.
Thanks, in advance. :)
Add overflow:hidden to div#content. This way we will get the proper height of the content div.
Now $('#content').height() + $('#content').offset().top is the maximum distance the sidebar should move. Which means, the sidebar's offset.top + height should not go more than this.
Add this check in your scroll handler
Set a limit for the top margin, since the sidebar can't go past the $('#main') element.
$(function() {
var offset = $("#ad-wrapper").offset();
var topPadding = 60;
$(window).scroll(function() {
var scrollTop = $(window).scrollTop(); // Store this for convenience
if (scrollTop > offset.top) {
var newMarginTop = scrollTop - offset.top + topPadding;
// The sidebar can only go so far!
var marginLimit = $('#main').height() + $('#main').offset().top - offset.top - $("#ad-wrapper").height();
if (newMarginTop > marginLimit)
newMarginTop = marginLimit;
$("#ad-wrapper").stop().animate({
marginTop: newMarginTop
});
} else {
$("#ad-wrapper").stop().animate({
marginTop: 0
});
}
});
});
How will you determine if you have reached the bottom of an element? For instance you have a div with a height of 2000px, then the viewport is only 600px tall. With these in place, how will you know how much scroll value you need to know if it's already the bottom of the 2000px div?
You can use something like this:
var $element = $('div');
$(window).scroll(function() {
var scroll = $(window).scrollTop() + $(window).height();
var offset = $element.offset().top + $element.height();
if (scroll > offset) {
$element.css('background', 'blue');
} else {
$element.css('background', 'red');
}
});
Demo: http://jsfiddle.net/eNjEs/5/
I have a sort of sidebar on my website, which has to scroll down together with the user so that it is always in the view.
The code I'm using now is actually working fine however there is one problem. On smaller screens the sidebar scrolls before your at the sidebar thus making it impossible to see it all even if you scroll.
So what I want is the sidebar to scroll with the bottom instead of it being pushed down with the top so that when you reach the end of the sidebar it starts to scroll.
This is the code that I'm currently using.
var documentHeight = 0;
var topPadding = 10;
$(function() {
var offset = $("#mainright").offset();
documentHeight = $(document).height();
$(window).scroll(function() {
var sideBarHeight = $("#mainright").height();
if ($(window).scrollTop() > offset.top) {
var newPosition = ($(window).scrollTop() - offset.top) + topPadding;
var maxPosition = documentHeight - (sideBarHeight);
if (newPosition > maxPosition) {
newPosition = maxPosition;
}
$("#mainright").stop().animate({
marginTop: newPosition
});
} else {
$("#mainright").stop().animate({
marginTop: 0
});
};
});
});
I guess the "best practice" for accomplishing a task like this is to use dynamically changing css position from absolute to fixed and vice versa. A basic example could look like:
$(function(){
var $box = $('.box'),
offset = $box.offset(),
doc_h = $(document).height();
$(window).scroll(function(){
if($(window).scrollTop() > offset.top) {
if(!$box.hasClass('fix'))
$box.toggleClass('normal fix');
}
else{
if(!$box.hasClass('normal'))
$box.toggleClass('normal fix');
}
});
});
Example in action: http://www.jsfiddle.net/YjC6y/14/
$(function() {
var top = 50;
$(window).scroll(function() {
$('#box').stop().animate({ top: $(window).scrollTop() + top}, 1000);
});
});
Try the example : http://jsbin.com/omiyi3
I think you can instead make the sidebar responsive by throwing your function into one of these:
if (responsive_viewport >= 768) {}
This makes it so that the function will only load if the viewport is bigger than or equal to 768px.