Sticky Sidebar that only sticks when sidebar bottom is at window bottom - javascript

I have a 2 column layout. The left column is way longer than the sidebar. I want the sidebar only to stick when its bottom reaches the bottom of the browser window. So the user can continue to scroll down the left column content while the right sidebar sticks. I've seen a lot of sticky questions here, however this particular situation still stumps me. I also have a sticking headline bar on the left column that i've successfully gotten to stick.
Here's a demo of what I've done in jsfiddle!
and here's a quick look at the js I am trying out.
$(function(){
var headlineBarPos = $('.headlineBar').offset().top; // returns number
var sidebarHeight = $('.sticky-sidebar-wrap').height();
var sidebarTop = $('.sticky-sidebar-wrap').offset().top;
var windowHeight = $(window).height();
var totalHeight = sidebarHeight + sidebarTop;
$(window).scroll(function(){ // scroll event
var windowTop = $(window).scrollTop(); // returns number
// fixing the headline bar
if (headlineBarPos < windowTop) {
$('.headlineBar').addClass('sticky').css('top', '0');
}
else {
$('.headlineBar').removeClass('sticky').removeAttr('style');
}
if(sidebarHeight < windowTop) {
$('.sticky-sidebar-wrap').addClass('sticky').css('top', '0');
} else {
$('.sticky-sidebar-wrap').removeClass('sticky').removeAttr('style');
}
console.log(windowTop);
});
console.log(headlineBarPos);
console.log(sidebarHeight);
console.log(sidebarTop);
});

I hope I got it right, when the bottom of the sidebar comes into the view, then stick?
I created another div at the bottom of the sidebar (inside the sidebar).
When that comes into view, it sticks.
http://jsfiddle.net/Z9RJW/10/
<div class="moduleController"></div> //inside the sidebar
and in js
$(function () {
var headlineBarPos = $('.headlineBar').offset().top; // returns number
var moduleControllerPos = $('.moduleController').offset().top; // returns number
var sidebarHeight = $('.sticky-sidebar-wrap').height();
var sidebarTop = $('.sticky-sidebar-wrap').offset().top;
var windowHeight = $(window).height();
var totalHeight = sidebarHeight + sidebarTop;
$(window).scroll(function () { // scroll event
var windowTop = $(window).scrollTop(); // returns number
// fixing the headline bar
if (headlineBarPos < windowTop) {
$('.headlineBar').addClass('sticky').css('top', '0');
} else {
$('.headlineBar').removeClass('sticky').removeAttr('style');
}
if (moduleControllerPos < windowTop + windowHeight) {
$('.sticky-sidebar-wrap').addClass('sticky').css('top', '0');
} else {
$('.sticky-sidebar-wrap').removeClass('sticky').removeAttr('style'); }
console.log(windowTop);
});
console.log(headlineBarPos);
console.log(sidebarHeight);
console.log(sidebarTop);
});
I hope it helps.

Something like:
if (sidebar.top + sidebar.height < window.scrolltop + window.height) {
// set sticky
}
and set sticky needs to take into account that the sidebar may be higher than the viewport, so:
sidebar.top = sidebar.height - window.height // this will be a negative number

Related

Sticky div - stop scrolling at certain point

I have a fixed div that follows the page when it scrolls past the top of the page.
I would like it to stop scrolling once it reaches the bottom of a particular div. I am not great with javascript.
Basically needs to remove the class .affix. But it might need an offset so that it doesn't overlap into the layout below.
I have looked at other articles but the div starts off fixed whereas mine becomes fixed.
JSfiddle: https://jsfiddle.net/8t1ddL2h/
Javascript:
var stickySidebar = $('.sticky-sidebar').offset().top;
$(window).scroll(function() {
if ($(window).scrollTop() > stickySidebar) {
$('.sticky-sidebar').addClass('affix');
}
else {
$('.sticky-sidebar').removeClass('affix');
}
});
Any help would be appreciated
Lee
Try this Fiddle
$(document).ready(function() {
var $sticky = $('.sticky-sidebar');
var $stickyrStopper = $('.other-content');
if (!!$sticky.offset()) { // make sure ".sticky" element exists
var generalSidebarHeight = $sticky.innerHeight();
var stickyTop = $sticky.offset().top;
var stickOffset = 0;
var stickyStopperPosition = $stickyrStopper.offset().top;
var stopPoint = stickyStopperPosition - generalSidebarHeight - stickOffset;
var diff = stopPoint + stickOffset;
$(window).scroll(function(){ // scroll event
var windowTop = $(window).scrollTop(); // returns number
if (stopPoint < windowTop) {
$sticky.css({ position: 'absolute', top: diff });
} else if (stickyTop < windowTop+stickOffset) {
$sticky.css({ position: 'fixed', top: stickOffset });
} else {
$sticky.css({position: 'absolute', top: 'initial'});
}
});
}
});
You can also try it just add JavaScript. it will automatic calculate height of left panel. you need to change in css when it remove the css.
var othercon = $('.other-content').offset().top;
var sliderheight = $( ".sticky-sidebar" ).height();
$(window).scroll(function() {
if ($(window).scrollTop() >= othercon-sliderheight) {
$('.sticky-sidebar').removeClass('affix');
// need to change here according to your need
}
});

Add class when element is at top of window

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');
}
});
}

Change scrollTop offset when scrolling up, and different offset on scrollDown

I got an issue, where I have an dynamic header that gets bigger when scrolling up and smaller when scrolling down and therefore needs to change scrollTop offsets.
So i've been looking around and tried with my no existent java skills with no success.
This jquery code:
$(document).on('click', 'a[href^="#"]', function(e) {
var id = $(this).attr('href');
var $id = $(id);
if ($id.length === 0) {
return;
}
e.preventDefault();
// top position relative to the document
var pos = $(id).offset().top-500; // move this one
$('body, html').animate({scrollTop: pos});
});
var iScrollPos = 0;
$(window).scroll(function () {
var iCurScrollPos = $(this).scrollTop();
if (iCurScrollPos > iScrollPos) {
var pos = $(id).offset().top-500; //here when scrolling down
} else {
var pos = $(id).offset().top-100; // Here when scrolling up
}
iScrollPos = iCurScrollPos;
});
I made a JS fiddle to show what I'm trying to achieve: https://jsfiddle.net/zq9y7nge/1/
So, Is it possible to change offset depending on scrolling up and down?

jQuery - sticky element is overlapping the footer, how to avoid it?

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});
}
[...]

Getting a floating div to stop upon reaching another div

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!

Categories

Resources