Dynamically change relatively positioned content to fixed content - bug - javascript

I have a sidebar that contains content larger than the screen. As the user scrolls down I want that content to come into view until the last bit. Then I want it to be fixed so that as much content stays on screen as possible. I actually want it to work exactly like the "Similar Questions" sidebar when you are posting a question in SO. In each of these example links scroll down. In the broken case notice how everything gets all jumpy.
Should work like this = http://jsfiddle.net/mrtsherman/G4Uqm/2/
But broken in this case = http://jsfiddle.net/mrtsherman/G4Uqm/1/
In the broken case it looks like the scroll event is being retriggered when you reach the end of the page. This then causes subsequent scroll events to trigger which then screw everything up. How can I properly handle this case? I just can't figure it out.
$(document).ready(function() {
var dynamic = false;
var topOfSidebar = $("#sidebar").offset().top;
var leftOfSidebar = $("#sidebar").offset().left;
var botOfSidebar = topOfSidebar + $("#sidebar").height();
var botOfScreen = $(window).height() + $(window).scrollTop();
//if sidebar fits on screen then use fixed version of it
if (botOfSidebar < $(window).height()) {
$("#sidebar").addClass("fixed");
$("#sidebar").css("top", topOfSidebar);
$("#sidebar").css("left", leftOfSidebar);
}
else {
dynamic = true;
}
//toggle sidebar class when user scrolls
$(window).scroll(function() {
console.log($("#sidebar").css("position"));
botOfScreen = $(window).height() + $(window).scrollTop();
//return;
if (botOfSidebar < botOfScreen && dynamic) {
$("#sidebar").addClass("fixed");
//$("#sidebar").css("bottom", 0);
//$("#sidebar").css("left", leftOfSidebar);
}
else if (dynamic) {
$("#sidebar").removeClass("fixed");
}
});
});

So I figured this one out on my own. The trick is to wrap the content in a div with a min-height attribute. If we switch the sidebar to fixed then the div holds the place of the sidebar. Therefore no more screen resizing.
.wrap creates the div
.parent gets the sidebar's parent (the new div)
add css properties where min-height is the height of the sidebar. Remove padding and margin
$("#sidebar")
.wrap('')
.parent()
.css("min-height", this.height())
.css("padding", "0px")
.css("margin", "0px");

Related

jQuery "unstick" box when scrolling before a certain threshold

I have a box that needs to stick, and I am using position: fixed CSS for that when it reaches the bottom of the page while scrolling, and then unstick while scrolling back up past that threshold. Below is my jQuery code:
$(window).scroll(function() {
var wHeight = $(window).height();
var stickyTop = $('.threshold').offset().top;
var xxx = stickyTop - wHeight;
var windowTop = $(window).scrollTop();
if ( windowTop > xxx ) {
console.log(windowTop)
$('.box').addClass("sticky")
} else {
$('.box').removeClass("sticky")
}
});
I don't understand why my else state doesn't work. And it's weird that the console.log kicks in late.
Here's a complete pen: https://codepen.io/frontend2020/pen/vYjJBma?editors=1010
Thanks for helping!
This kind of sticking effect can be easily done with CSS. If you want something similar like this YouTube video which was captured on this site, you just need two nested divs (i.e.div>div).
The parent div must has larger height (let's say 1000px) and child div can be anything less than the parent div (let's say 200px). Then you just need to apply position: sticky; to child div.
That will do the trick.

Translate div on scroll

I have a div in a div.
The first div has a unknown height. The second one has the height of 125px.
I want to make the second one a sticky div which is only sticky in this div.
The grey box is the container and the social media div next to it should be sticky.
After the container more content will come, so I cant use position: fixed. I tried to use position: absolute and change the top value or the transform: translate, but when I Do that Chrome is jittering around.
Code that I tried to use:
$offset = $(".social-media").offset().top;
$containerHeight = $(".sticky-container").height();
$bottom = $containerHeight + $(".sticky-container").offset().top;
$maxPoint = $containerHeight - $(".social-media").height();
$(window).scroll(function(){
if($(window).scrollTop() >= $offset){
if($(window).scrollTop() >= $bottom){
$(".social-media").css({transform: "translate(0px,"+$maxPoint+"px)"});
}else{
$scroll = $(window).scrollTop() - $offset;
$(".social-media").css({transform: "translate(0px,"+$scroll+"px)"});
}
}else{
$(".social-media").css({transform: "translate(0px,0px)"});
}
});
Since the jsbin you provided shows the solution works without jittering, the problem might lie in the repaints triggered by other elements of your site, not the code you pasted. Have a look at the Google's repaint optimization guidelines, it might help you identify the issues that cause the jittering.

Fixing an element when it reaches the top of the page

I currently have a script that fixes a <header> element after a certain amount of scrolling. How would I modify it so that the element scrolls normally until it gets to the top of the page then fixes. Something like this.
Current code:
$(document).ready(function(){
// Fix Sidebar
windowHeight = $(window).height();
sidebarHeight = $(".sidebar").height() + 70;
console.log(sidebarHeight + ", " + windowHeight);
if (windowHeight > sidebarHeight) {
$('.sidebar').addClass("affix");
}
});
N.B. .affix is just {position:fixed}.
Site
The <header> element is the sidebar on the right with the big green demo button.
To make your sidebar fixed when the user scrolls down and reaches the top of the sidebar, use Jquery to add a class name to the sidebar when it reaches the window top position and add the position:fixed style to this new class.
var stickySidebar = $('.sidebar').offset().top;
$(window).scroll(function() {
if ($(window).scrollTop() > stickySidebar) {
$('.sidebar').addClass('affix');
}
else {
$('.sidebar').removeClass('affix');
}
});
This will add a class name affix to the sidebar when the user scrolls down and reaches the top of the sidebar. Now add the fixed position to the sidebar with class name affix.
.sidebar.affix{
position:fixed;
top:0;
right:0;
}
DEMO
I believe you may be looking for something like this: http://stickyjs.com/ (scroll to see it in action, you can do this to any element on a page). If that isn't what you are looking for let me know and I will help come up with something that suits your needs.

How to keep content of a div always visible despite moving scrollbar down

I am trying to duplicate the left nav at http://www.kahuna-webstudio.fr/. If you take a look at http://www.kahuna-webstudio.fr/, and scroll down about 50 pixels or so, you will see a div appear off to the left of the screen that has some navigation in it. I have most of it working, thanks to the help of some of you at stackoverflow. But the one part I do not have working is that the content of my div, images, do not stay stationary in place (or always visible) as you scroll down.
So what I want to happen is: when the div appears at the left of the screen, when the user scrolls down, I want the content of the div to appear always in view.
Right now what I have working is: through animate() I set the height of my left nav div to the document height, and the width grows to 80 pixels, and then some images fadeIn(). But the page is fairly long and as the user scrolls down they are also able to scroll down the height of my left nav div; and I always want the content of my left nav to always appear in view to the user.
I think this person posted a similiar question (Keeping a header always in view) but I am finding it difficult to attach if to my example code. Can anyone help? I appreciate it a lot.
Here is my code:
$(window).scroll(function(){
var wintop = $(window).scrollTop();
var docheight = $(document).height();
var winheight = $(window).height();
var newwidthgrow = 80;
var smallheight = 0;
var smallwidth = 0;
if((wintop > 296)) {
$("#slidebottom").stop().animate({height:docheight +"px"},'fast',function(){
$("#slidebottom").stop().animate({width:newwidthgrow + "px"},'slow',function(){
$("#slidebottomContents").fadeIn();
});
});
}
if((wintop < 25))
{
$("#slidebottom").stop().animate({height:docheight +"px"},'fast',function(){
$("#slidebottomContents").fadeOut(function(){
$("#slidebottom").stop().animate({width:smallwidth + "px"});
});
});
}
});
As far as i'm concerned this can be covered by only css.
To keep the div in the same position you can apply the following css:
css:
div id {
position: fixed;
left: 0px
width: 'your width'
}
position fixed freezes the div in the position you want.
left keeps the div positioned on the left side of you page.
does this answer your question and solve your problem?
if not let me know!

Keeping sidebar in viewport, problem with scrolling

I've got a solution for keeping a sidebar in the viewport as you scroll up and down the page. Problem comes in when the sidebar is longer than the content area, and you keep scrolling you get this jittering effect as the sidebar keeps pushing the footer down.
I've got an example of this setup in jsFiddle: http://jsfiddle.net/U9F7w/2/ (full screen: http://jsfiddle.net/U9F7w/2/embedded/result/ )
My question is, is there a way to make the sidebar stop once it touches the bottom/footer area?
I've read some solutions about setting the sidebar to absolute, unfortunately it's an existing site and changing the position didn't work and messed with a lot of the existing page elements.
Here's the jQuery/js I'm working with:
// set the offset
var sidebarOffset = $(".sidebar").offset();
var sidebarPadding = 15;
// when the window scrolls, keep sidebar in view
$(window).scroll(function() {
if ($(window).scrollTop() > sidebarOffset.top) {
$(".sidebar").stop().animate({marginTop: $(window).scrollTop() - sidebarOffset.top + sidebarPadding });
}
else {
$(".sidebar").stop().animate({marginTop: 0});
};
});
edit
One thing I thought about was (not sure if this is possible) to detect if the bottom of one div was lower than the bottom of another, stop the scrolling. Is there a way to detect if the bottom of one div is lower than the other?
Check if the sidebar's height is greater then that of the content:
var ct = $(".content");
var sb = $(".sidebar");
var sbOffsetTop = sb.offset().top;
var sbPadding = 15;
$(window).scroll(function() {
if (sb.height() < ct.height()) {
if ($(window).scrollTop() > sbOffsetTop) {
sb.stop().animate({top: $(window).scrollTop() - sbOffsetTop + sbPadding });
}
else {
sb.stop().animate({top: 0});
};
};
});
See demo fiddle with large content and demo fiddle with large sidebar.
And I don't know why exactly, I would use top in conjunction with position: relative, but marginTop works also fine.

Categories

Resources