Flickering element on fixed sidebar on top scroll using offset - javascript

I'm trying to create a fixed sidebar menu. Everything works fine but the sidebar element is flickering once you scroll to the top if you had scroll below.
var windowHeight = $(window).height();
var headerHeight = $('.js-site-header').outerHeight();
var sidebarThreeBlocks = (windowHeight-headerHeight)/3;
var sidebarTwoBlocks = (windowHeight-headerHeight)/2;
var sidebar = $('.js-sidebar');
$('.js-triple-nav a').css({height: sidebarThreeBlocks});
$('.js-double-nav a').css({height: sidebarTwoBlocks});
if (!!sidebar.offset()) {
$(window).scroll(function(){
var stickyTopSidebar = sidebar.offset().top;
var windowTop = ($(window).scrollTop())+headerHeight;
if (stickyTopSidebar < windowTop) {
sidebar.css({ top: windowTop });
}
else {
sidebar.css({ top: '3.125em' });
}
});
}
I used to put the var stickyTopSidebar = sidebar.offset().top; above with all the other variables but I would always get an error on the javascript console as it seemed the variable was undefined. Even so, the sidebar then worked perfectly, with no flickers but all the rest of javascript wouldn't work. Any hints or help?

Related

javascript issue with fixed position side menu

I'm building a website with a sidebar that, once the user scrolls past a certain point it becomes fixed on the site. This code works fine.
The issue that I am coming into is that the sidebar is overlapping the footer when the user scrolls to the bottom of the page. I wrote code to detect when the bottom of the sidebar hits the same position as it's containing element - when that happens I am taking the position of the bottom of the containing element and subtract the height of the sidebar element and using that number to give the sidebar it's new "top" (while also changing the position to "absolute").
This is where I am running into the issue - once the sidebar is overtop of the footer as the user scrolls the code that is getting called alternates between the normal "fixed" position code and the "absolute" positioned code giving it this flickering effect.
For the life of me I can't figure out why the "fixed" code keeps getting called.
Here is the code:
( function( $ ) {
var sidebar_pos = $('#secondary')[0].getBoundingClientRect();
var pos_top = sidebar_pos.top + window.scrollY; //need this to get the pos of TOP in the browser - NOT the viewport
var main_pos = $('.main-content')[0].getBoundingClientRect();
var main_bottom = main_pos.bottom + window.scrollY;
var stop_pos;
var i = 0;
$(window).scroll(function(event){
var scroll = $(window).scrollTop();
var produce_pos = $('.produce')[0].getBoundingClientRect();
var pos_bottom = produce_pos.bottom + window.scrollY;
//console.log("scroll "+scroll);
//console.log("top " + pos_top);
console.log(main_bottom);
console.log('bottom ' + pos_bottom);
if( scroll >= pos_top){
if ( pos_bottom >= main_bottom ){
//if the sidebar would end up overlapping the footer
if(i == 0){
//only need to set this once, not on every scroll
stop_pos = main_bottom - $('#secondary').height() ;
}
$('#secondary').removeClass('hover').css({
position: 'absolute',
margin:0,
left: sidebar_pos.left,
top: stop_pos
});
i++;
} else {
$('#secondary').addClass('hover').css({
position: 'fixed',
left: sidebar_pos.left,
marginTop: '1.5em',
top: 20
});
setTimeout(() => {
$('*[data-widget="comet"]').addClass('active');
}, 5000);
setTimeout(() => {
$('*[data-widget="produce"]').addClass('active');
}, 7000);
}
} else if( scroll < pos_top && $('#secondary').hasClass('hover') ){ //if user scrolls up past original pos of sidebar, remove effects
$('#secondary').removeClass('hover').css({
position: 'relative',
left: 'auto',
top: 'auto'
});
i = 0;
}
});
}( jQuery ) );
I also have a codepen of the script in action.
https://codepen.io/antlaur00/pen/ExyrgYR
Any help is much appreciated! Thanks!
Well its pretty simple, just add Z-index property to your footer CSS, that way it will always overlap your sidebar .
You can refer to this article regarding the z-index property
https://www.w3schools.com/cssref/pr_pos_z-index.asp

top value for element should be around -22px, but is somehow around -254px

So what I am doing simplified is adding 3 to the top value of #searchInput, which should be -22px before on scroll up.
But according to the console.log and the fact that I can't see the #searchInput on scroll up, the top value is around -254.
It is incremmenting up by 3 properly, but I don't know where that first number came from. It should be -22.
How can I fix it?
Here is the URL: https://googledrive.com/host/0BwJVaMrY8QdcdVZDcm1uVkJaUlE/KE_home.html
To replicate it:
Scroll down until the header is no longer in view
scroll up, but not enough so that the header is back in view
Here is my script:
var lastScrollTop = 0;
$(window).scroll(function(){
console.log($('#searchInput').css('top'));
var st = $(this).scrollTop();
if(st<=lastScrollTop){
if(!isElementInViewport(document.getElementById('header'))){
var pixelsScrollMoved = $(this).scrollTop();
$('#searchInput').addClass('slideBack');
while(parseFloat($('#searchInput').css('top'))<=32){
var last_pixelsScrollMoved = pixelsScrollMoved;
pixelsScrollMoved = $(this).scrollTop();
if(last_pixelsScrollMoved = pixelsScrollMoved + 1){
$('#searchInput').css('top', parseFloat($('#searchInput').css('top'))+3+'px');
console.log('moved up one!');
}
break;
}
$('#headerTopBar').css('position', 'fixed').css('top', '0').fadeIn();
}
else{
console.log('header in viewport');
}
}
lastScrollTop = st;
});

Fixed Navigation Menu after Scrolll

I'm trying to create a sticky navigation menu that will be positioned right underneath a banner and when you scroll down and the banner cannot be seen anymore the navigation menu will be fixed at the top of the browser chrome. Here's what I have so far: http://tinyurl.com/bper44a
The CSS is straight forward, the issue may be with my JS:
$(document).ready(function() {
var s = $(".navMenu");
var pos = s.position();
$(window).scroll(function() {
var windowpos = $(window).scrollTop();
if (windowpos >= pos.top) {
s.addClass("fixedTop"); }
else {
s.removeClass("fixedTop");
}
});
});
While it works exactly the way on want it in Firefox, I can figure out why it behaves differently in Chrome and Safari (gets into fixed position as soon as you scroll down just a little bit).
Any insight?
Not sure why it works in firefox, but I think the following will work for all browsers:
$(document).ready(function() {
var s = $(".navMenu");
var banner = $("header > img");
$(window).scroll(function() {
var windowpos = $(window).scrollTop();
// if the scroll position is greater than the height of the banner
// fix the navigation.
if (windowpos >= banner.outerHeight()) {
s.addClass("fixedTop"); }
else {
s.removeClass("fixedTop");
}
});
});
Obligatory fiddle here.

Change margin-top as user scrolls

I am trying to get a div to scroll up at the same amount of pixels as the user scrolls down the page. For example, in Google Chrome when using the mouse wheel, it scrolls down in about 20px intervals. But when you scroll down using the handle, the scrolling amount varies.
Here is my code so far:
var scrollCtr = 50;
$(window).scroll(function(){
scrollCtr = scrollCtr - 20;
$('div.nexus-files').css('margin-top', scrollCtr + 'px');
});
There are a few problems with this:
The user scrolling varies
It needs to subtract from margin-top if scrolling down and add to margin-top if scrolling up
Here is an example:
http://www.enflick.com/
Thanks for the help
You're doing it the wrong way, what you are trying to do should be done using position: fixed on div.nexus-files
div.nexus-files{position: fixed; top: 0;}
but anyway - if you still want to know what you can do with the scroll event - you better get to scrollTop of the document and set the margin-top to the same value
window.onscroll = function(event){
var doc = document.documentElement, body = document.body;
var top = (doc && doc.scrollTop || body && body.scrollTop || 0);
document.getElementById('nexus-files_id').style.marginTop = top+'px';
}
I'm using pure Javascript instead of jQuery because of the overhead that might be crucial when the browser need to calculate stuff in a very short amount of time (during the scrolling). [this can be done even more efficient by storing reference to the element and the doc... but you know..)
I used id based selector to get the specific element instead of class based
AND I SAY AGAIN - this is not how you should do what you were trying to do
Why not using the actual scroll offset as reference or position ?
// or whatever offset you need
var scrollOffset = document.body.scrollTop + 20;
// jQuery
var scrollOffset = $("body").scrollTop() + 20;
Finally Got it
Here is the code I used to accomplish the task.
Most of the code is from http://enflick.com and I modified it to work with my individual situation.
jQuery(window).load(function(){
initParallax();
});
// parallax init
function initParallax(){
var win = jQuery(window);
var wrapper = jQuery('#wrapper');
var bg1 = wrapper.find('.nexus-files');
var koeff = 0.55;
if (bg1.length) {
function refreshPosition(){
var scrolled = win.scrollTop();
var maxOffsetY1 = 450;
var offsetY1 = scrolled * koeff;
var offsetY2 = scrolled * koeff - (maxOffsetY1 * koeff - offsetY1);
if (offsetY1 <= maxOffsetY1 * koeff - offsetY1) {
bg1.css("margin-top", +-offsetY1+"px");
//alert(+-offsetY1+"px");
}
}
refreshPosition();
win.bind('resize scroll', refreshPosition);
}
}

Position fixed related parent container

I need solution to emulate fixed position, but relative parent div, not whole viewport. JS solutions are laggy. I need fixed related parent container, because if window has small height, div with fixed position enters into footer zone.
Example
Another approach re your update.
Try giving the fixed div z-index: 10;
And the footer div position: relative; z-index: 11
That should make the footer overlap the fixed div.
then it's not an issue of position:fixed, maybe you could just define a min-height to your body (or on the main wrapper if any) to avoid the short page problem
I have combined css and js:
$(document).ready(function () {
var $sidebar = $(".register-box"),
$window = $(window),
$content = $("#content"),
docHeight = $(document).height();
var entered = false;
$window.scroll(function () {
if ($window.height() < 795 && docHeight - $window.scrollTop() < 785) {
entered = true;
var pos = $sidebar.offset();
$sidebar.css('position', 'absolute').css('top', ($content.height() - ($sidebar.height() + 40)) + 'px');
}
else {
if (entered) {
entered = false;
$sidebar.css({
top: "",
left: "",
position: "fixed"
});
}
}
});
});
Code is not final, and numbers are hard coded, but it works, smooth enough.

Categories