I have a main header (#top-bar) with page navigation and a sub-navigation bar (#category-bar) with links to sections on the page. The sub-navigation bar loads on the bottom of the screen, then as the user scrolls down the sub-navigation bar pushes the fixed position main header off screen by changing it to absolute position. The sub-navigation bar becomes fixed to the top. This all works fine with waypoints js triggering different position states for the bars.
I now need to have the main header reappear on scroll up. Here is my javascript so far, though it does not effect the header on scroll up:
function moveHeader() {
var topBar = '#top-bar',
var stickyElement = jQuery('#category-bar');
var bottomBarOffset = stickyElement.offset();
var topOffset = jQuery(topBar).offset().top; //get the offset top of the element
jQuery(stickyElement).waypoint({
handler: function(direction) {
if (direction === 'down') {
jQuery(topBar).css({ position: 'absolute', top: bottomBarOffset.top - jQuery(topBar).outerHeight() });
}
else {
jQuery(topBar).attr('style', '');
}
},
offset: topBarHeight - 1,
});
jQuery(topBar).waypoint({
handler: function(direction) {
if (direction === 'up') {
jQuery(this.element).addClass('pin');
}
else {
jQuery(this.element).removeClass('pin');
}
},
offset: topOffset - jQuery(window).scrollTop() - 100, //attempt to trigger main header pushed off screen top
});
}
I have tried different calculations to trigger the #top-bar without any luck. Does anyone have advice for the calculation or different approach for this project?
After reading more related SO topics and some tests with waypoints js, I abandoned waypoints js for this portion of the script. I created a function for calculating the trigger point for setting the fixed header. The variable calculation constantly changed on scroll up, which caused waypoints to continually fire and create a flickering effect. This made me realize that this implementation is not the proper use for waypoints. My solution implements a simple scroll up / scroll down jQuery function after leaving the top section. In this script, it is set to fire on a 20 pixel scroll in either direction:
function moveHeader() {
var topBar = '#top-bar',
var stickyElement = '#category-bar';
var bottomBarOffset = jQuery(stickyElement).offset();
var topBarOffset = jQuery(topBar).offset().top;
jQuery(stickyElement).waypoint({
handler: function(direction) {
if (direction === 'down') {
jQuery(topBar).css({ position: 'absolute', top: bottomBarOffset.top - jQuery(topBar).outerHeight() });
}
else {
jQuery(topBar).attr('style', '');
}
},
offset: topBarHeight - 1,
});
jQuery(function(){
var lastScrollTop = 0;
var scrollDistance = 20;
if (jQuery('body').hasClass('page-template-page-sections-menu')) {
jQuery(window).scroll(function(event){
var st = jQuery(this).scrollTop();
if(Math.abs(lastScrollTop - st) <= scrollDistance)
return;
if (st > lastScrollTop && st > windowHeight && jQuery('body').hasClass('scroll-up'))
{
// downscroll code
jQuery('body').addClass('scroll-dn');
jQuery('body').removeClass('scroll-up');
jQuery(stickyElement).attr('style', '');
} else if (st < lastScrollTop && st > windowHeight)
{
// upscroll code
jQuery('body').addClass('scroll-up');
jQuery('body').removeClass('scroll-dn');
jQuery(topBar).attr('style', '');
jQuery(stickyElement).attr('style', '');
} else if (st < lastScrollTop && st < windowMinusTop)
{
// upscroll and first section (window height from top of document)
jQuery(stickyElement).css({ 'z-index': '0' });
jQuery('body').removeClass('scroll-up scroll-dn');
}
lastScrollTop = st;
});
};
});
}
This solution achieves what my client needs, though I am open to any further improvements.
Related
Im using a script to detect scroll up to click a previous link. I want to detect scroll up even when your top of the page and do a scroll up. Now I have to scroll down a bit then up again. How can I do this?
Code:
var lastScrollTop = 0, delta = 5;
jQuery(window).scroll(function(){
var nowScrollTop = jQuery(this).scrollTop();
if(Math.abs(lastScrollTop - nowScrollTop) >= delta){
if (nowScrollTop > lastScrollTop){
// ACTION ON
// SCROLLING DOWN
} else {
jQuery( 'a.action.previous' ).click ();
}
lastScrollTop = nowScrollTop;
}
});
I am trying to transfer between display:none, and display:block. The div with the id #octopus-head is supposed to fade out when scrolling down, and back in when scrolling up, but right now it just pops in or out instantly.
Here is the javascript I am working with:
//sticky header scripts
// Hide Header on on scroll down
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = jQuery('.scroll-height-setter').innerHeight();
jQuery(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 100);
function hasScrolled() {
var st = jQuery(this).scrollTop();
// Make sure they scroll more than delta
if(Math.abs(lastScrollTop - st) <= delta)
return;
// If they scrolled down and are past the navbar, add class .nav-up.
// This is necessary so you never see what is "behind" the navbar.
if (st > lastScrollTop && st > navbarHeight){
// Scroll Down
jQuery('#octopus-head').removeClass('nav-down').addClass('nav-up').fadeOut(1000);
} else {
// Scroll Up
if(st + jQuery(window).height() < jQuery(document).height()) {
jQuery('#octopus-head').removeClass('nav-up').addClass('nav-down').fadeIn(1000);
}
}
lastScrollTop = st;
}
Display none cannot use transitions as there is nothing to transition from.
You could use setTimeout() to add a transition class that renders the div with opacity of zero and then switch classes to your final opacity 100%.
Or you could just always use opacity and never display none the div. It depends on what you actually need.
I'm trying to create sticky headers that when you scroll to a div the head state becomes fixed and stays in view, when the div has come to an end and scrolls out of view I want the title to then become absolute and stay at the bottom of its parent.
I've got the initial part working only I'm struggling on adding the 'absolute' class...
https://jsfiddle.net/yw313vf2/1/
function fixTitle() {
$('.service-pane').each(function() {
var $this = $(this);
var offset = $this.offset().top;
var scrollTop = $(window).scrollTop();
if (scrollTop > offset) {
$this.addClass('fixed');
} else {
$this.removeClass('fixed');
}
});
}
$(window).scroll(fixTitle);
So I had to run another check within the function to see if when scrolled the end of my div had reached the top of the window and if so add an additional class...
function fixTitle() {
$('.service-pane').each(function() {
var $this = $(this);
var offset = $this.offset().top - 50;
var scrollTop = $(window).scrollTop();
if (scrollTop > offset) {
$this.addClass('fixed');
if ($this[0].getBoundingClientRect().bottom < $('.manifesto').height() + 50) {
$this.addClass('absolute');
} else {
$this.removeClass('absolute');
}
} else {
$this.removeClass('fixed');
}
});
}
I have a sticky sidebar working on my project, but when you go to the bottom of the page, the sticky sidebar is overlapping my footer.
What I want is that when the sticky element reach the footer, then stop just right there so the user can see the entire footer.
here is a demonstration of what I have so far.
or a jsfiddle in case it is easier for you
this is the code:
var stickySidebar = $('.sticky');
if (stickySidebar.length > 0) {
var stickyHeight = stickySidebar.height(),
sidebarTop = stickySidebar.offset().top;
}
// on scroll move the sidebar
$(window).scroll(function () {
if (stickySidebar.length > 0) {
var scrollTop = $(window).scrollTop() + 70;
if (sidebarTop < scrollTop) {
stickySidebar.stop(true, false).animate({top: scrollTop - sidebarTop});
// stop the sticky sidebar at the footer to avoid overlapping
var sidebarBottom = stickySidebar.offset().top + stickyHeight,
stickyStop = $('.main-content').offset().top + $('.main-content').height();
if (stickyStop < sidebarBottom) {
var stopPosition = $('.main-content').height() - stickyHeight;
stickySidebar.stop(true, true).animate({top: stopPosition});
}
}
else {
stickySidebar.stop().animate({top: 0});
}
}
});
$(window).resize(function () {
if (stickySidebar.length > 0) {
stickyHeight = stickySidebar.height();
}
});
This is maybe not perfect, but I think it gives you the right idea, how to solve this problem. You just have to check, if the bottom of the sidebar is below the top position of the footer. Than stop the animation.
http://jsfiddle.net/hdj99b21/1/
[...]
var stickyTopPos = stickySidebar.offset().top;
var stickyBottomPos = stickyHeight + stickyTopPos;
var footerTopPos = $('footer').offset().top;
if(stickyBottomPos >= footerTopPos) {
var stopPosition = footerTopPos - stickyHeight;
stickySidebar.stop(true, true).css({top: stopPosition});
}
[...]
I have a floating div on the sidebar that scrolls with the page. Is there a way to add code that makes it stop when it reaches the footer?
See code in action: http://openbayou.staging.wpengine.com
jQuery code used to float div:
$j=jQuery.noConflict();
$j(document).ready(function($) {
//this is the floating content
var $floatingbox = $('#one');
if($('#primary').length > 0){
var bodyY = parseInt($('#primary').offset().top) - 20;
var originalX = $floatingbox.css('margin-left');
$(window).scroll(function () {
var scrollY = $(window).scrollTop();
var isfixed = $floatingbox.css('position') == 'fixed';
if($floatingbox.length > 0){
$floatingbox.html();
if ( scrollY > 1561 && !isfixed ) {
$floatingbox.stop().css({
position: 'fixed',
top: 10,
});
} else if ( scrollY < 1561 && isfixed ) {
$floatingbox.css({
position: 'relative',
top: 0,
});
}
}
});
}
});
Why not just set the z-index of the sidebar behind the z-index of the footer?
EDIT: I didn't like the result of this so I went and made this work in jquery the way you want it...
try this for your scroll function:
$(window).scroll(function () {
floatingbox = $("#one");
if(floatingbox.length > 0){
//get our current scroll position
var scrollY = $(window).scrollTop();
//get the position of the tag cloud relative to the document
var contentY = ($("#sidebar .sidebar-tag-cloud").offset().top + $("#sidebar .sidebar-tag-cloud").outerHeight(false));
//calculate the largest possible top margin size before it starts to overlap the footer
var lastY = $("#footer").offset().top - $("#one").outerHeight(false);
//check if our scroll location is past the bottom of the tag cloud
if ( scrollY > contentY )
{
//check if the current top position is less than the maximum position
if(floatingbox.offset().top<lastY)
{
//keep scrolling
floatingbox.stop().animate({"marginTop":scrollY-contentY});
}else
{
//check if we have scrolled back up and have a space at the top
if(scrollY<floatingbox.offset().top)
{
floatingbox.stop().animate({"marginTop":scrollY-contentY});
}else
{
// hard set to the maximum position
floatingbox.stop().css({"marginTop":lastY-contentY});
}
}
}
}
});
I also made it a little more dynamic by getting the location of the bottom of the tag cloud and using that instead of your hard-coded number.
Alright, after looking at your latest jsfiddle. I have modified that code to work with yours. http://jsfiddle.net/Tgm6Y/4430/ This will not have the animate lag and should work well for you.
$('#one').followTo('#two','#pointFive');
just replace #two with #footer and #pointFive with "#sidebar .sidebar-tag-cloud" and this should work in your code.
UPDATE: Found a solution to my problem.
$(function () {
var msie6 = $.browser == 'msie' && $.browser.version < 7;
if (!msie6) {
var top = $('#one').offset().top;
$(window).scroll(function (event) {
var y = $(this).scrollTop() + 20;
if (y >= top) {
$('#one').addClass('fixed');
}
else {
$('#one').removeClass('fixed');
}
// don't overlap the footer - pull sidebar up using a negative margin
footertotop = ($('#footer').position().top);
scrolltop = $(document).scrollTop() + 760;
difference = scrolltop - footertotop;
if (scrolltop > footertotop) {
$('#one').css('margin-top', 0 - difference);
}
else {
$('#one').css('margin-top', 0);
}
});
}
});
What this does is it stops before the footer and I can configure the stopping point.
I appreciate all the help in solving my problem!