Here is my idea:
List item a black border that follow scroll on nav
List item
scroll to a <div> on click
it's hard to explain (I'm french) so just try it on:
http://mathieualbore.com/traci/
It work when you click from smilio > skiply but not working if start from skiply and click > smilio
the code :
$("#smilio").waypoint({
handler: function(event, direction) {
left = $('.menu li[data-target="#smilio"]').position().left;
w = $('.menu li[data-target="#smilio"] span').width();
$('.active').stop().animate({ left: left, width: w+40 })
},
offset: 40
});
$("#skiply").waypoint({
handler:
function(event, direction) {
left = $('.menu li[data-target="#skiply"]').position().left;
w = $('.menu li[data-target="#skiply"] span').width();
$('.active').stop().animate({ left: left, width: w+40 })
},
offset: 40
});
and
$(".menu li").click(function() {
var target = $(this).data("target");
var scrollY = $(target).position().top;
$("html, body").animate({ scrollTop: scrollY-40 }, 500);
}
I find a way to do the trick if someone is interested
$(".menu li, a").click(function() {
var target = $(this).data("target");
var scrollY = $(target).position().top;
$("html, body").animate({
scrollTop: scrollY-40
}, 500, function() {
left = $('.menu li[data-target="'+target+'"]').position().left;
w = $('.menu li[data-target="'+target+'"]').width();
$('.active').stop().animate({
left: left,
width: w+40
})
});
});
And this to simplify waypoints :
$(".menu li").each(function() {
var target = $(this).data("target");
$(target).waypoint({
handler: function(event, direction) {
left = $('.menu li[data-target="'+target+'"]').position().left;
w = $('.menu li[data-target="'+target+'"]').width();
$('.active').stop().animate({ left: left, width: w+40 })
},
offset: 40
});
});
Related
I have a navigation area that turns into a sticky header once you scroll past it and I also have a smooth scrolling function to scroll the page to specific sections when you click on different links. The problem I am having is that if you click one of the links before the navigation becomes sticky, the page scrolls too far past the section because the offset is using the initial height of the navigation rather than the sticky height. The same thing happens in the opposite direction as well, if you click on the link to the first section, it scrolls too far up because it uses the height of the sticky nav as the offset. Is there an easy way to solve for this?
$(function() {
// Smooth scrolling
$('nav li').click(function() {
var navHeight = $('nav').height();
var section = $(this).attr('class');
var target = $('#'+section);
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - navHeight
}, 750);
return false;
}
});
// Sticky nav
var navTop = $('nav').offset().top;
var stickyNav = function() {
var scrollTop = $(window).scrollTop();
if (scrollTop > navTop) {
$('nav').addClass('sticky');
} else {
$('nav').removeClass('sticky');
}
};
stickyNav();
$(window).scroll(function() {
stickyNav();
});
});
JSFiddle example
You might be able to just add the 'sticky' class to the nav when the user clicks on an element.
$(function() {
// Smooth scrolling
$('nav li').click(function() {
var section = $(this).attr('class');
var target = $('#'+section);
if (target.length) {
if (target.offset().top > navTop){
$('nav').addClass('sticky');
}
var navHeight = $('nav').height();
$('html,body').animate({
scrollTop: target.offset().top - navHeight
}, 750);
return false;
}
});
// Sticky nav
var navTop = $('nav').offset().top;
var stickyNav = function() {
var scrollTop = $(window).scrollTop();
if (scrollTop > navTop) {
$('nav').addClass('sticky');
} else {
$('nav').removeClass('sticky');
}
};
stickyNav();
$(window).scroll(function() {
stickyNav();
});
});
I have a list of items. The format is something like this:
||||||||||||||||||||||||||||||
| SPACER DIV |
||||||||||||||||||||||||||||||
| ELEMENT DIV |
| |
||||||||||||||||||||||||||||||
| SPACER DIV |
||||||||||||||||||||||||||||||
| ELEMENT DIV |
| |
||||||||||||||||||||||||||||||
I am using a jQuery script to move a element up/down the list:
$(sortableContainer).on('click', '.sortable-controls i', function(e){
var that = $(e.target);
var item = that.closest(panel);
var thisWindow = $(window);
var scrollTop = thisWindow.scrollTop(),
elementOffsetTop = item.offset().top,
distanceTop = (elementOffsetTop - scrollTop);
if(that.hasClass('sortable-up')) {
var filler = item.prev();
var prev = item.prevAll(panel).first();
if (prev.length == 0)
return;
item.prev().remove();
prev.css('z-index', 999).css('position','relative').animate({
top: item.height()
}, 250);
item.css('z-index', 1000).css('position', 'relative').animate({ top: '-' + prev.height(), queue: false}, 300, function () {
prev.css('z-index', '').css('top', '').css('position', '');
item.css('z-index', '').css('top', '').css('position', '');
item.insertBefore(prev);
filler.insertBefore(prev);
Abayo.builder.updateSorted(item, sortableContainer);
});
var scrollDifference = distanceTop - prev.height() - filler.height();
$("html, body").animate({ scrollTop: scrollDifference, queue: false }, 300);
} else if(that.hasClass('sortable-down')) {
var filler = item.next();
var next = item.nextAll(panel).first();
if (next.length == 0)
return;
item.next().remove();
next.css('z-index', 999).css('position', 'relative').animate({
top: '-' + item.height()
}, 250);
item.css('z-index', 1000).css('position', 'relative').animate({ top: next.height(), queue: false }, 300, function () {
next.css('z-index', '').css('top', '').css('position', '');
item.css('z-index', '').css('top', '').css('position', '');
item.insertAfter(next);
filler.insertAfter(next);
Abayo.builder.updateSorted(item, sortableContainer);
});
$("html, body").animate({ scrollTop: distanceTop + next.height() + filler.height(), queue: false }, 300);
}
})
Sadly this doesn't work well when the element is not exactly in the middle and there are enough elements to create a overflow-y.
How to change this script in that it always keep the element in viewport and also consider the viewport size?
I must be able to click a top element all the way down, but after a few clicks the down-button falls outside my viewport, and I have to manually scroll to continue this.
JSFIDDLE
If I use the element's offset it seems to stop the element from leaving the viewport:
$("html, body").animate({ scrollTop: prev.offset().top - 50, queue: false }, 300);
$("html, body").animate({ scrollTop: next.offset().top, queue: false }, 300);
I have found out what I did wrong.
I first needed to calculate what the current offsetTop of the viewport was.
var scroll = thisWindow.scrollTop(),
elementOffset = item.offset().top,
distance = (elementOffset - scroll);
The distance calculated is just the distance from the element to the viewport.
To get the current offset I just had to substract the calculated distance from the item.offset().top. Then I just needed to substract/add the prev/next item height:
Element up:
$("html, body").animate({ scrollTop: elementOffset - distance - prev.height(), queue: false }, 300);
Element down:
$("html, body").animate({ scrollTop: elementOffset - distance + next.height(), queue: false }, 300);
JsFiddle
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
How do I make a max height?
animate( { height: '500px' } to animate( { height: '100%' }
I have some heights with 200px 300px 400px 800px.
$(document).ready(function() {
$("#updo").click(function(){
$("#updo_folder").stop();
$("#updo_folder").show();
if($("#updo_folder").height() < 1){
$("#updo_folder").animate( { height: '500px' }, 1000 , function(){$(this).show();});
}else{
$("#updo_folder").animate( { height: '0px' }, 1000, function(){$(this).hide();});
}
});
});
var jump=function(e)
{
e.preventDefault();
var target = $(this).attr("href");
$('html,body').animate(
{
scrollTop: $(target).offset().top
},500,function()
{
location.hash = target;
});
}
$(document).ready(function()
{
$('a[href*=#]').bind("click", jump);
return false;
});
http://jsfiddle.net/prffrost/TFBeu/4/
You set height: 100%, measure it, then set height: 0px again and animate to that height:
$(document).ready(function () {
$("#updo").click(function () {
// Use a variable rather than endlessly repeating the lookup
var folder = $("#updo_folder");
var targetHeight;
folder.stop().show();
if (folder.height() < 1) {
// Set it to full height
folder.css("height", "100%");
// Measure it
targetHeight = folder.height();
// Set back to zero height, and animate to the measured height
folder.css("height", "0px");
folder.animate({
height: targetHeight
}, 1000, function () {
$(this).show();
});
} else {
folder.animate({
height: '0px'
}, 1000, function () {
$(this).hide();
});
}
});
});
Updated Fiddle
I have a back to top button that fades in at certain points on scroll. I am looking to change the script so instead of fading in and out that the button slides left 50px then slides right -50px; (off the screen)
Here is my code for fading in and out:
var offset = 220;
var duration = 500;
$(window).scroll(function() {
if (jQuery(this).scrollTop() > offset) {
$('.back-to-top').fadeIn(duration);
} else {
$('.back-to-top').fadeOut(duration);
}
});
$('.back-to-top').click(function(event) {
event.preventDefault();
$('html, body').animate({scrollTop: 0}, duration);
return false;
})
I tried this but its not working for me:
var offset = 220;
var duration = 500;
$(window).scroll(function() {
if (jQuery(this).scrollTop() > offset) {
$('.back-to-top').animate({ "left": "+=50px" }, duration );
} else {
$('.back-to-top').animate({ "right": "+=50px" }, duration );
}
});
Any help would be greatly appreciated.
Try this...
$(window).scroll(function() {
if (jQuery(this).scrollTop() > offset) {
$('.back-to-top').animate({"left":"-50px"}, "slow").removeClass('visible');
} else {
$('.back-to-top').animate({"left":"50px"}, "slow").addClass('visible');
}
});
or you can use the jquery UI based example..like this
$('.back-to-top').hide('slide', {direction: 'left'}, 1000);
How abt this one :-
var offset = 220;
var duration = 500;
$(window).scroll(function() {
if (jQuery(this).scrollTop() > offset) {
$('.back-to-top').animate({ "right": "+100px" }, duration );
} else {
$('.back-to-top').animate({ "left": "0px" }, duration );
}
});