Sticky navigation issue with touch devices - javascript

Have created a sticky menu, which is working fine for desktop and mobiles.
But there is a small issue with mobiles, when ever scrolling the page and the finger is still on the screen then
after reaching to the position of the container where the menu needs to stick it is not happening.
When I removed the finger from the screen, then it is taking a second time and the menu is getting fixed.
is there any solution for this, kindly help me with a sample demo.
Demo
JS:
var menuSection = $('.section') , navLists = $('.menu ul li'),
navLists_height = navLists.outerHeight(), headerOffset = $('.top_layer').offset().top;
$(window).on('scroll', function () {
var window_top = $(window).scrollTop() + 12;
if (window_top > headerOffset) {
$('.menu').addClass('fixed');
} else {
$('.menu').removeClass('fixed');
}
var cur_position = $(this).scrollTop()+70;
menuSection.each(function() {
var top = $(this).offset().top - navLists_height,
bottom = top + $(this).outerHeight();
if (cur_position >= top && cur_position <= bottom) {
navLists.find('a').removeClass('active');
menuSection.removeClass('active');
$(this).addClass('active');
navLists.find('a[href="#'+$(this).attr('id')+'"]').addClass('active');
}
});
});
navLists.find('a').on('click', function () {
var $el = $(this)
, id = $el.attr('href');
$('html, body').animate({
scrollTop: $(id).offset().top - navLists_height
}, 500);
return false;
});

Related

jQuery scrollTop() returns wrong offset on scroll-direction change

I'm trying to get the correct scroll direction via jQuery's "scroll" event.
For this, I'm using the solution here: https://stackoverflow.com/a/4326907/8407840
However, if I change the direction of my scroll, the offset returned by scrollTop is incorrect on the first time. This results in the following behavior:
Wheel down -> down
Wheel down -> down
Wheel up -> down
Wheel up -> up
Wheel down -> up
Wheel down -> down
... and so on, I think you get it.
var ACTIVE_SECTION = null;
var ANIMATION_DURATION = 700;
$(document).ready(function() {
ACTIVE_SECTION = $("section:first-of-type").get(0);
var prevPosition = $(window).scrollTop();
$(window).on("scroll", function() {
doScrollingStuff(prevPosition);
});
});
function doScrollingStuff(prevPosition) {
var ctPosition = $(window).scrollTop();
var nextSection = ACTIVE_SECTION;
// Remove and re-append event, to prevent it from firing too often.
$(window).off("scroll");
setTimeout(function() {
$(window).on("scroll", function() {
doScrollingStuff(prevPosition);
});
}, ANIMATION_DURATION + 100);
// Determine scroll direction and target the next section
if(ctPosition < prevPosition) {
console.log("up");
nextSection = $(ACTIVE_SECTION).prev("section").get(0);
} else if(ctPosition > prevPosition) {
console.log("down");
nextSection = $(ACTIVE_SECTION).next("section").get(0);
}
// If a next section exists: Scroll to it!
if(typeof nextSection != 'undefined') {
var offset = $(nextSection).offset();
$("body, html").animate({
scrollTop: offset.top
}, ANIMATION_DURATION);
ACTIVE_SECTION = nextSection;
} else {
nextSection = ACTIVE_SECTION;
}
console.log(ACTIVE_SECTION);
prevPosition = ctPosition;
}
section {
width:100%;
height:100vh;
padding:60px;
box-sizing:border-box;
}
section:nth-child(1) { background:#13F399; }
section:nth-child(2) { background:#14FD43; }
section:nth-child(3) { background:#4EE61E; }
section:nth-child(4) { background:#BEFD14; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="sect1">Section 1</section>
<section id="sect2">Section 2</section>
<section id="sect3">Section 3</section>
<section id="sect4">Section 4</section>
Here's a pen, where you can see my implementation: https://codepen.io/EigenDerArtige/pen/aVEyxd
I am trying to accomplish an autoscroll to the next or previous section, whenever the user scrolls or swipes up/down... Therefore I only fire the "scroll"-event once every second, to prevent multiple scrolljacks all happening at once... However the above behavior seems to result in the user being scrolled to the wrong section.
I've been trying for a couple of hours now to get it working, but to no avail. Help is greatly appreciated!
The problem lies in the assignment prevPosition = ctPosition.
Each time the scroll handler runs, var ctPosition = $(window).scrollTop(); is good for determining scroll direction, however it's not the value that should be rememberad as prevPosition.
prevPosition needs to be $(window).scrollTop() as measured after the animation has completed.
Try this :
$(document).ready(function() {
var ANIMATION_DURATION = 700;
var ACTIVE_SECTION = $("section:first-of-type").eq(0);
var prevPosition = $(window).scrollTop();
$(window).on("scroll", doScrollingStuff);
function doScrollingStuff(e) {
$(window).off("scroll");
var ctPosition = $(window).scrollTop();
var nextSection = (ctPosition < prevPosition) ? ACTIVE_SECTION.prev("section") : (ctPosition > prevPosition) ? ACTIVE_SECTION.next("section") : ACTIVE_SECTION; // Determine scroll direction and target the next section
// If next section exists and is not current section: Scroll to it!
if(nextSection.length > 0 && nextSection !== ACTIVE_SECTION) {
$("body, html").animate({
'scrollTop': nextSection.offset().top
}, ANIMATION_DURATION).promise().then(function() {
// when animation is complete
prevPosition = $(window).scrollTop(); // remember remeasured .scrollTop()
ACTIVE_SECTION = nextSection; // remember active section
$(window).on("scroll", doScrollingStuff); // no need for additional delay after animation
});
} else {
setTimeout(function() {
$(window).on("scroll", doScrollingStuff);
}, 100); // Debounce
}
}
});

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?

Scrolling issue while sticking header and setting the tab active | Jquery

I have developed a page, which has a fixed menu once the page is scrolled and also the tabs will become active on their appropriate section id's.
I have almost completed the functionality but I am facing some problems :
Scrolling is not appropriate and it is not stopping at the exact position of the container. Example : If i scroll to section3, the tab should get select once the section3 container hits, but I need to scroll a little bit to get the tab selected.
Once I click on the tab, then the page is getting freezed unable to do any scroll on the page neither able to select any other tab.
i have seen lot of demo's and tried but failed to implement. as per my knowledge i did this demo.
Please help me out with the current code change where I have done wrong.
this is what I tried.
demo Link
HTML:
<div class="top_layer">Top Layer</div>
<div class='menu'>
<ul>
<li>basic 1</li>
<li>basic 2</li>
<li>basic 3</li>
<li>basic 4</li>
</ul>
</div>
<div id="basic1" class="section">basic 1</div>
<div id="basic2" class="section">basic 2</div>
<div id="basic3" class="section">basic 3</div>
<div id="basic4" class="section">basic 4</div>
JS:
var menuSection = $('.section') , navLists = $('.menu ul li'),
navLists_height = navLists.outerHeight(), headerOffset = $('.top_layer').offset().top;
$(window).on('scroll', function () {
var window_top = $(window).scrollTop() + 12;
if (window_top > headerOffset) {
$('.menu').addClass('fixed');
} else {
$('.menu').removeClass('fixed');
}
var cur_position = $(this).scrollTop();
menuSection.each(function() {
var top = $(this).offset().top - navLists_height,
bottom = top + $(this).outerHeight();
if (cur_position >= top && cur_position <= bottom) {
navLists.find('a').removeClass('active');
menuSection.removeClass('active');
$(this).addClass('active');
navLists.find('a[href="#'+$(this).attr('id')+'"]').addClass('active');
}
});
navLists.find('a').on('click', function () {
var $el = $(this)
, id = $el.attr('href');
$('html, body').animate({
scrollTop: $(id).offset().top - navLists_height
}, 500);
return false;
});
});
I have update the code , check fiddle , your navlist selecting anchors should be outsideof window scroll.
var menuSection = $('.section'),
navLists = $('.menu ul li'),
navLists_height = navLists.outerHeight(),
headerOffset = $('.top_layer').offset().top;
$(window).on('scroll', function() {
var window_top = $(window).scrollTop() + 12;
if (window_top > headerOffset) {
$('.menu').addClass('fixed');
} else {
$('.menu').removeClass('fixed');
}
var cur_position = $(this).scrollTop() + 70;//70 for fixed header height
menuSection.each(function() {
var top = $(this).offset().top - navLists_height,
bottom = top + $(this).outerHeight();
if (cur_position >= top && cur_position <= bottom) {
navLists.find('a').removeClass('active');
menuSection.removeClass('active');
$(this).addClass('active');
navLists.find('a[href="#' + $(this).attr('id') + '"]').addClass('active');
}
});
});
navLists.find('a').on('click', function() {
var $el = $(this),
id = $el.attr('href');
$('html, body').animate({
scrollTop: $(id).offset().top - navLists_height
}, 500);
return false;
});

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

Categories

Resources