Stop element from being fixed once scrolled past value - javascript

I have a fixed .widget element that remains visible at all times. Currently however, it scrolls over the footer area. My goal is to stop the widget before it hits the footer.
CSS
.widget {
position:fixed;
height:450px;
width:300px;
}
footer {
height:450px;
width:100%;
}
My route I'm taking is currently:
jQuery
var $bodyheight = $('body').height();
var $footerheight = $('footer').height();
var $widgetheight = $('.game_widget').height();
var $pageheight = $bodyheight - $footerheight - $widgetheight;
$(window).on('scroll', function() {
console.log($(this).scrollTop())
});
My next step would be to loop through to see if scrollTop > $pageheight then update some CSS.
Is this the best way of going about this? Is there a cleaner/simpler way to achieve the same result?

I have managed to solve this quite simply. Inside the scroll function I set 2 variables, one for the position of the fixed element, the other for the position of the footer. These return the exact value from how far the top of the element is from the top of the page. For the fixed element I need to know the distance to the bottom of this element so I also include the height.
var $fixedpos = $(".game_widget").offset().top + $('.game_widget').height();
var $footerpos = $("footer").offset().top - 25; // 25 accounts for margin
Using a simple if/else the CSS is updated to display none/initial depending on whether $fixedpos > $footerpos (i.e. the fixed element is overlapping the footer).
if ($fixedpos > $footerpos) {
$('.game_widget').css('display','none');
} else {
$('.game_widget').css('display','initial');
}
This works, however there is a 'flicking' effect as the fixed element overlaps the footer. This is due to the function executing extremely rapidly. The solution to the flicker is to use this simple 'throttling' plugin that adds a short delay (of your choice) between each execution of a function - http://benalman.com/projects/jquery-throttle-debounce-plugin/
You then just need to bind the on scroll function to the throttle:
function scrolling() {
console.log($(".game_widget").offset().top + $('.game_widget').height());
console.log($("footer").offset().top - 25);
var $fixedpos = $(".game_widget").offset().top + $('.game_widget').height();
var $footerpos = $("footer").offset().top - 25;
if ($fixedpos > $footerpos) {
$('.game_widget').css('display', 'none');
} else {
$('.game_widget').css('display', 'initial');
}
};
$(window).on('scroll', $.throttle(250, scrolling)); // 250ms between executing the function
});
This 250ms delay stops the function from executing so rapidly that the flickering effect occurs.
Hope this helps others trying to solve this problem.

Related

Sticky navigation bar doesn't work properly

I'm using this code to make the navigation bar stick to the top of the page after scrolling:
var nav=$('body');
var scrolled=false;
$(window).scroll(function(){
if(175<$(window).scrollTop()&&!scrolled){
nav.addClass('stuck');
$('.navigation-class').animate({marginTop:80},1000);
scrolled=true;
}
if(175>$(window).scrollTop()&&scrolled){
$('.navigation-class').animate({marginTop:0},0,function(){nav.removeClass('stuck');$('.navigation-class').removeAttr('style');});
scrolled=false;
}
});
The problem is, if the user scrolls the page up and down quickly, and the navigation is STILL animating, it will continue the animation and then suddenly jump into it's designed position, which gives a hiccup effect to the menu.
Try to scroll this page quickly to see it in live.
Is it possible to make it run smoothly like other websites?
Thanks are in order.
Edit:
After rereading the question, I realized the problem is probably that you're not cancelling the animation when the user scrolls back above 175px.
Presumably you're applying position: float to your nav element? Are you removing float as soon as the user scrolls up?
Try setting the queue option to false (see https://api.jquery.com/animate/), so the animation doesn't wait for the other one to complete.
Maybe you could try getting rid of the JQuery animation and replacing it with CSS transitions?
Maybe something like this?
var nav=$('body');
var scrolled=false;
var scrollToggle = function(){
$(window).off('scroll');
if(175<$(window).scrollTop()&&!scrolled){
nav.addClass('stuck');
$('.navigation-class').animate({marginTop:80},1000, function() {
$(window).on('scroll', scrollToggle);
);
scrolled=true;
}
else if(175>$(window).scrollTop()&&scrolled){
$('.navigation-class').animate({marginTop:0},0,function({
nav.removeClass('stuck');
$('.navigation-class').removeAttr('style');
$(window).on('scroll', scrollToggle);
});
scrolled=false;
}
};
$(window).on('scroll', scrollToggle);
I have something similar in a WIP myself. I'll post it here only slightly edited, maybe it can be useful to you.
var headerFloat = function() {
//Header
var pageHeader = $('#pageHeader'), pos = '',
headerMain = $('#headerMain'), headerMainHeight = '',
content = $('#content'), contentPadding = '',
pageTitle = $('h1.currentPage'), pageTitleTop = '';
if($(window).scrollTop() >= 95) {
pos = "fixed";
headerMainHeight = '75px';
contentPadding = '225px';
pageTitleTop = '55px';
contentHeaderTop = '130px';
}
//Header
pageHeader.css('position', pos);
headerMain.css('height', headerMainHeight);
content.css('padding-top', contentPadding);
pageTitle.css({ 'transition': 'all 0s', 'position': pos, 'top': pageTitleTop });
pageTitle[0].offsetHeight; //force "reflow" of element -- stackoverflow.com/questions/11131875/#16575811
pageTitle.css('transition', '');
};
$(document).ready(function() {
/* *** SCROLL -> FLOAT HEADER *** */
$(window).on("scroll.float", headerFloat);
});
Inputting '' (empty string) in the JQuery css function resets it to the original value. You should do that instead of .removeAttr('style');
I would also avoid the scrolled boolean. I think you need it anyway, if scrollTop < 175, you'll never be scrolled, and vice versa.

Position fixed, but scroll on <body>

I have this situation:
my website, which I am creating, has a left sidebar, which must be set to height 100%, while scrolling the webpage, and the content inside it is definitely over 1000px height.
because of the height of the content, I get vertical scroll on this sidebar element, and when my content has enough content, I get another scroll for this section.
What I have to do is to, somehow, transfer, scroll from the "fixed" element to the main page scroll...
I hope that you can understand me...
I hope that this screenshot, can also help you to understand what I ask:
link
Thank you in advance for you answers.
Your question got me interested, so I gave it a try.
You could have your sidebar set up like so:
#sidebar{
position:fixed;
min-height:100%;
top:0;
left:0;
/* ... */
}
Now, to make it scroll, we can play with its margin-top css property:
If we scroll down, we decrement it unless we scrolled past its
height.
If we scroll up, we increment it unless it's above zero.
I created a ScrollingSidebar class with 2 functions in order to deal with that:
// ScrollingSidebar class
// Define some variables and bind events
function ScrollingSidebar(el){
this.sidebar = el;
var that = this;
that.updateVariables();
document.addEventListener('scroll',function(){that.scrollSidebar();});
window.addEventListener('resize',function(){that.updateVariables();});
}
// Updates variables used for calculation
ScrollingSidebar.prototype.updateVariables = function(){
this.height = parseInt( getComputedStyle(this.sidebar).height );
document.body.style.minHeight = this.height + 'px';
this.winHeight = parseInt( window.innerHeight );
this.previousScrollPos = Math.floor( document.body.scrollTop ||
document.documentElement.scrollTop ||
document.body.parentNode.scrollTop
);
this.scrollSidebar();
};
// Updates the sidebar's margin-top
ScrollingSidebar.prototype.scrollSidebar = function(){
var curScrollPos = Math.floor( document.body.scrollTop ||
document.documentElement.scrollTop ||
document.body.parentNode.scrollTop
);
if(this.previousScrollPos < curScrollPos){
this.sidebar.style.marginTop = - Math.min(-parseInt( getComputedStyle(this.sidebar).marginTop ) + (curScrollPos - this.previousScrollPos),
this.height-this.winHeight) + 'px';
} else {
this.sidebar.style.marginTop = Math.min(0,parseInt( getComputedStyle(this.sidebar).marginTop ) + this.previousScrollPos-curScrollPos) + 'px';
}
this.previousScrollPos = curScrollPos;
};
You can use it like so:
// Create an instance of ScrollingSidebar
var sidebar = document.getElementById('sidebar');
var x = new ScrollingSidebar(sidebar);
JS Fiddle Demo (with a small amount of content)
JS Fiddle Demo (with a lot of content)
Note: I did not take the time to comment my code very well, but if you have any question about it or any problem with it, feel free to ask.
If your website is responsive and you don't want this method to be used on small screens, you might want to consider using a condition to disable it.

How to Smoothly Prevent a Fixed Element from Scrolling Past A Specified Element

Essentially what I want to do is keep my blog posts' meta information on the screen at all times. As it is, the meta info (title, author, etc.) is displayed to the left of the post content, and I have it set up where the meta information stays on screen smoothly when I scroll down. However, I'm having an issue:
I can't get it to smoothly not scroll over the #comments DIV. It either overlaps or is jumpy, depending on how I tweak the code.
Here is the JS function I'm using:
function brazenlyScroll() {
var element = jQuery(".single-post .headline_area");
var top = element.offset().top - 50;
var elementHeight = 26 + element.height();
var maxTop = jQuery("#comments").offset().top - elementHeight;
var scrollHandler = function() {
if (jQuery(document).width() > 1035) {
var scrollTop = jQuery(window).scrollTop();
if (scrollTop<top) {
element.css({position:"relative",top:""})
} else if (scrollTop>maxTop) {
element.css({position:"absolute",top:(maxTop+"px")})
} else {
element.css({position:"fixed",top:"50px"})
}
}
}
jQuery(window).scroll(scrollHandler);
jQuery(window).resize(scrollHandler);
scrollHandler();
}
That code is included via an external JS file and is called at the bottom of the page. You can see all of this in action here: http://www.rickbeckman.org/dumber-and-dumber-and-dumber/
Any help would be greatly appreciated.
You can make the comments div shrink to right by giving it a 300px padding when meta block reaches maxTop.
I just tested ur code and was able to fix the overlapping by changing 26 to a bigger number, say about 60.
var elementHeight = 26 + element.height();
Hope this helps.

Box-sizing: border-box is causing an error on a JS fixed position sidebar, on scroll

I have some javascript that applies a fixed class to my sidebar, so when you scroll, the menu stays with you. Stackoverflow has this with the similar questions sidebar.
$(function() {
var top = $('.side-menu').offset().top - parseFloat($('.side-menu').css('margin-top').replace(/auto/, 0));
$(window).scroll(function (event) {
// what the y position of the scroll is
var y = $(this).scrollTop();
// whether that's below the form
if (y >= top) {
// if so, ad the fixed class
$('.side-menu').addClass('fixed');
$('body').addClass('fixed-sidebar');
} else {
// otherwise remove it
$('.side-menu').removeClass('fixed');
$('body').removeClass('fixed-sidebar');
}
});
});
In my CSS I have * { box-sizing: border-box; } which is causing the else to fire off and the page jumps. When I removed the box-sizing, the fixed menu works as desired.
My question is
Is there another way to achieve what i'm trying to do?
Is there a way to unset the box-sizing property?
EDIT
User this link for a demo: Resize the browser window at various heights and you'll see the issue. http://dev.danielcgold.com/fixed-menu.html
You can always do (selector) { box-sizing: content-box } of course. (That will "unset" your box-sizing...)

Adjust top position according to height of div with javascript

function jsiBoxAdjustTop()
{
var top
if ( jsiBox.preloadImg.height <= 699){
top = 216;
}
else{
top = 17;
}
jsiBox.boxNode.style.top = (top) + 'px';
}
I'm using that function to adjust a div's top position depending on the image that is in it's height. It's on a light box sort of script so every time I click the next button, a new image which could either be taller or smaller appears. It's working alright and it adjusts its position when the image is taller but my problem is it just jumps to that position. I'm really new to javascript so can anyone help me out to make this as if it's travelling/animating to it's position? I tried using setTimeOut but I think I was doing it wrong. I'd really love to know what I'm doing wrong.
Here's the full script if that helps. Link
you can use jQuery or YUI to do animate, such as
jQuery(jsiBox.boxNode).animate({'top': top}, 3000);
or you can write some simple code with setTimeout just for this case;
following code assume the begin top is 0.
var boxStyle = jsiBox.boxNode.style;
function animateTop(to) {
boxStyle.top = parseInt(boxStyle.top, 10) + 1 + 'px';
if (parseInt(boxStyle.top, 10) != to) {
setTimeout(function() {
animate(to);
}, 50);
}
}
animateTop(top);

Categories