Sticky sidebar is jolty if its shorter than the window height? - javascript

I have a sticky sidebar that when you scroll becomes fixed when the bottom of the sidebar is in view.
If the sidebar exceeds the length of the page as it does in this demo all works fine when you scroll and is exactly what you would expect.
However if the sidebar is shorter than the window height as in this demo, it seems to be jumping when you scroll and I can't work out how to get it to stop jumping and to be smooth. In other words it should only be fixed when the base of the sidebar hits the base of the window.
I'm not great with jQuery so any help would be greatly appreciated.
$(function () {
if ($('.leftsidebar').offset()!=null) {
var top = $('.leftsidebar').offset().top - parseFloat($('.leftsidebar').css('margin-top').replace(/auto/, 0));
var height = $('.leftsidebar').height();
var winHeight = $(window).height();
var footerTop = $('#footer').offset().top - parseFloat($('#footer').css('margin-top').replace(/auto/, 0));
var gap = 7;
$(window).scroll(function (event) {
// what the y position of the scroll is
var y = $(this).scrollTop();
// whether that's below the form
if (y+winHeight >= top+ height+gap && y+winHeight<=footerTop) {
// if so, ad the fixed class
$('.leftsidebar').addClass('leftsidebarfixed').css('top', winHeight-height-gap +'px');
}
else if (y+winHeight>footerTop) {
// if so, ad the fixed class
$('.leftsidebar').addClass('leftsidebarfixed').css('top', footerTop-height-y-gap + 'px');
}
else {
// otherwise remove it
$('.leftsidebar').removeClass('leftsidebarfixed').css('top', '0px');
}
});
}
});
Is it possible to combine the two instances? So if its shorter stay relative till the sidebar reaches the bottom, then act as it is now if the sidebar is longer?

The code works just as intended. This is actually a conceptual problem.
Picture how it would work first. The way you described it working seems to be exactly how it's working in your demo. When the sidebar is longer than the page, the scrolling page reaches the bottom of the sidebar before the leftsidebarfixed is added. That would be impossible with a shorter sidebar.
You may want to consider fixing the sidebar to the top, instead of the bottom (as most websites with sticky sidebars do) or having a taller header, so that the sidebar starts at the bottom.

Related

Sticky Bootstrap column should end with parent/content

I have seen various forms of this problem but nothing really helped me to solve the partial sticky sidebar/Bootstrap column behaviour. Let me start with the problem itself.
There is a big image close to the top of my page. Because of the page complexity, I am using Bootstrap column grid. The image spans over, let's say, 10 columns and I have left 2, belonging to the same row, on the left side to store a sidebar. This also allows me to vertically align the sidebar next to the image.
Now, the sidebar, what is now a Bootstrap column, should go sticky and should stay vertically aligned to the viewport once the scrollbar passes by. You can see in the fiddle that it kind of "jumps" instead of transitioning smoothly.
The other problem is that the sticky element/column should only remain sticky as long as its parent/container is visible. Which means that it should transition/be relative to the end of that container. Right now I have only managed to keep it sticky till the end of the page. It should stop above the red line (depicted in the fiddle).
Here is my jQuery logic so far.
$(document).ready(function(){
$(window).scroll(function(){
var elem = $("#refScroller").offset().top - ($("#refScroller").height() / 2);
var windowvalue = $(window).scrollTop();
if (elem <= windowvalue) {
$("#wannabeSticky").addClass("sticky");
}
else {
$("#wannabeSticky").removeClass("sticky");
}
});
});
I would really appreciate some ideas and hints as this has been bothering me for two days. I would love to keep the Bootstrap grid structure if possible, but feel free to give any suggestions, even those who depict the sidebar as a pure absolute div, as long as the sticky-ness works.
Thanks in advance!
EDIT: I know there is a similar problem already here, but it seems I can't make the JS logic work for my case.
So, having spent another day on it, it seems I reached a decent jQuery version that gets the job done. There is my updated fiddle.
$(document).ready(function(){
var passedMobileNavi = false;
function stickySocialNavi(reference, valueExtracted) {
var refTop = $(reference).offset().top - valueExtracted;
var scrollTop = $(window).scrollTop();
return (refTop <= scrollTop);
}
$(window).scroll(function() {
if (stickySocialNavi($("#refScroller"), $("#refScroller").height())) {
if (!passedMobileNavi) {
passedMobileNavi = true;
$("#wannabeSticky").addClass("sticky");
}
}
else {
passedMobileNavi = false;
$("#wannabeSticky").removeClass("sticky");
}
if (stickySocialNavi($("#end"), $(window).height())) {
var var1 = $(window).scrollTop(),
var2 = $("#end").offset().top,
var3 = $(window).height();
var calculateOffset = (var2 - var3) - var1;
$("#wannabeSticky").css("top", "calc(50% + " + calculateOffset + "px)");
}
else {
$("#wannabeSticky").css("top", "50%");
}
});
});
For the sticky-ness to start, I took the reference point (which is the non-moving element right next to it) and its height. The sticky element gets a fixed position as long as the scrollbar goes past the reference point's center.
As the stick element is centered, it gets additional top offset values when the end of its container is reached. It is still fixed, but its top property's value takes the scroll difference, thus slowly depicting it towards the end of the container.
I don't know if this is the most elegant, straightforward, or easy to implement/understand solution, but it worked for me.

Fix div when scrolled at its bottom

I have a collapsible aside nav (so don't know the height of it) and a div under it, which should change position to fixed when scrolled at it's bottom.
I achieved this, but when I scroll back at top, the div stays fixed and I can't find solution to make it static again at the point where it was at the beginning, since I don't know where the exact point is.
Here is a fiddle (I explain my solution in js comments): https://jsfiddle.net/1krLnv7q/2/.
Could anybode help me, please? I am stuck.
EDIT
You can define your vars outside of the scroll() event, otherwise it will cause a buggy animation.
Like this
$(function(){
//top offset of static/fixed div
var staticOffset = $('.static').offset().top;
//window height
var wpHeight = $(window).height();
//point when the user scrolls at the bottom of div
//static/fixed div height + top offset - viewport height
var treshold = staticOffset + $('.static').height() - wpHeight;
$(window).scroll(function(){
//if user scrolls below the divs bottom (treshold) it becomes fixed
if ($(window).scrollTop() > treshold){
$('.static').addClass('fix');
}else{
$('.static').removeClass('fix');
}
});
});

Script to stop fixed div from scrolling under another div?

https://rebecca-milazzo-test.squarespace.com/featured#/btr/
I have the page meta-data set to fixed positioning, but as the users scroll, the div doesn't stop and scrolls under the thumbnails at the bottom of the page. I have researched other scripts, but they all are created to stop the div at a certain pixel height and not another element.
Any help is greatly appreciated.
You're going to want to create a function that checks the windows scroll position to see whether you've scrolled to the thumbnails section. When you've scrolled to the thumbnails section, set the fixed elements position to absolute and set its top to the windows scroll position plus the original top value. For those like myself who thought z-index would suffice, OP doesn't want the element to go either underneath the thumbnails section or above the thumbnails section on scroll.
function checkposition(){
fixedelement = document.querySelector(".project-meta");
stopelement = document.querySelector("#project-thumbs");
stoppoint = stopelement.scrollTop - fixedelement.clientHeight - parseInt(fixedelement.style.top);
if (window.scrollY >= stoppoint){
fixedelement.style.position = "absolute";
fixedelement.style.top = [defaulttophere] + window.scrollY + "px";
} else {
fixedelement.style.position = "fixed";
fixedelement.style.top = [defaulttophere];
}
}
window.addEventListener("scroll", checkposition);
Let me know if this works or not, I threw this together pretty quickly.

Freeze element (position:fixed) for specific scroll range

I'm working on this site (http://styleguide.co/medhelp/) that has 5 sections. For one of the sections (Styles), I've got a sidenav I'm trying to get to stick in the visible frame only as long as users are scrolling in that section.
Here's what I've done thus far - I'm telling the section title & sidenav to stick after the top of the section has begun:
$(window).scroll(function(event) {
var sw = $('.fixed'),
pg = $('.styles'),
diff = pg[0].offsetTop - window.pageYOffset;
if (diff < 80 ) {
$('.fixed').css('position', 'fixed');
$('.fixed').css('top', '160px');
$('.styles').css('position', 'fixed');
$('.styles').css('top', '70px');
}
else {
$('.fixed').css('position', 'relative');
$('.fixed').css('top', '0px');
$('.styles').css('position', 'relative');
$('.styles').css('top', '0px');
}
});
I can't seem to figure out a good way to make the section title "Style" and the sidenav appear/disappear while I scroll to/from that section. Any advice? What could I do better? A simple solution demo in jsfiddle would really help!
Please click on this link & scroll down/up to know what I'm referring to: http://styleguide.co/medhelp/
I'm not going to give you a fiddle, but you need to determine when the next section would stick based on its offset from the top. At the moment what you are doing is:
// if difference top and element < 80 -> fix to top, else position is relative
First of all this means the condition will never be undone. What you need to do in order to continue is:
// once next contact section comes into screen
//(offset from the top of the screen <= screen height), give
var winHeight = $(window).height();
var calcTop = 80 - (winHeight - (winHeight - $('#nextSelector').offset().top);
$('.fixed').css('top', calcTop);
This will give the illusion of your text scrolling up as the new section comes up. I hope this helps. Also, when scrolling back up it doesn't re-stick, but you probably are aware of that.

Sidebar move after user scrolls down x amount

Let's get straight to it: When the user scrolls x amount, I want the sidebar to begin to move.. Now, once the sidebar reaches its' end, I want it to stay fixed and scroll to the footer. Here's what I got.
http://jsfiddle.net/Ajp44/
Here's my Javascript:
$(document).ready(function() {
// Cache selectors for faster performance.
var $window = $(window),
$sidebar = $('#anchor'),
$sidebarAnchor = $('#right');
// Run this on scroll events.
$window.scroll(function() {
var window_top = $window.scrollTop();
var div_top = $sidebarAnchor.offset().top;
if (window_top > div_top) {
// Make the div sticky.
$sidebar.addClass('stick');
$sidebarAnchor.height($sidebar.height());
}
else {
// Unstick the div.
$sidebar.removeClass('stick');
$sidebarAnchor.height(0);
}
});
});
For some reason JSfiddle isn't displaying what the Javascript is doing, but if you run it on your PC you can see. Whenever the user scrolls passed the ending of the sidebar, the sidebar doesn't scroll down with them like it is suppose to, instead, it jumps of to the right side of the page...
So my question is this: how do I stop the sidebar from jumping to the side of the page, and keep it within the restraints of the parent DIV?
Cheers!
Don't do right : 0 in your stick class. In fixed elements, the position attributes are relative to the viewport.
https://developer.mozilla.org/en-US/docs/Web/CSS/position#Fixed_positioning

Categories