Show/Hide Sub-Header based on Scroll position - javascript

Question: I am trying to accomplish the following animation: When the page loads in mobile I want to show the div with the ID "sub-header" but as soon as the user scrolls more than 50px down the page I want to .hide sub-header. Finally if the user scrolls up 60px anytime while on the page I want sub-header to .show
What I am seeing with the code below: The page hides the menu but when I scroll up it shows and hides multiple times after I stop scrolling.
JQuery:
var newScroll = 0;
var subHeaderPosition = true;
var currentScroll = 0;
$(window).scroll(function () {
currentScroll = $(window).scrollTop();
if ($(window).width() < 779) {
if (currentScroll > 50 && subHeaderPosition) {
console.log("Current Scroll position: " + currentScroll);
console.log("Scroll should hide");
$("#sub-header").hide(300);
subHeaderPosition = false;
newScroll = $(window).scrollTop();
console.log("New Scroll position: " + newScroll);
} else if ((currentScroll - 60) < newScroll && !subHeaderPosition) {
console.log("Scroll position: " + currentScroll);
console.log("Scroll should show Sub-Header");
$("#sub-header").show(300);
subHeaderPosition = true;
newScroll = $(window).scrollTop();
} else {
newScroll = $(window).scrollTop();
}
}
});
UPDATE: After adding a few more logs I can now tell that my newscroll and currentscroll are always ending up the same number which points me in the right direction. I will post a solution once I have it or if anyone figures it out I am all ears.

You can use this for fixing issue
$(function(){
$(window).on('scroll', function(){
if($(window).scrollTop() >= 50){
$('header').addClass('hide');
}
else if($(window).scrollTop() <= 60){
$('header').removeClass('hide');
}
});
});
https://jsfiddle.net/qummetov_/3hf1e350/

I guess there is a problem with hide/show time arguments. Because of it, while the hide action could done, the scroll actually asynchronously doing.
Checkout jsfiddle.
I'm checking this correctivity with the canShowHeader variable.
In my case I'm running a fake setTimeout, but you can use original jquery hide/show case:
Example:
$( "#book" ).show(300, function() {
canShowHeader = false;
});
and
$( "#book" ).hide(300, function() {
canShowHeader = true;
});
Hope It helps...

I'm thinking of using addClass and removeClass, as #Ниязи Гумметов has said, because you can only remove and add a class once.
Something like this:
var newScroll = 0;
var subHeaderPosition = true;
var currentScroll = 0;
$(window).scroll(function() {
currentScroll = $(window).scrollTop();
if (currentScroll > 50 && subHeaderPosition) {
console.log("Current Scroll position: " + currentScroll);
console.log("Scroll should hide");
$("#sub-header").removeClass("show");
$("#sub-header").addClass("hide");
subHeaderPosition = false;
newScroll = $(window).scrollTop();
console.log("New Scroll position: " + newScroll);
} else if ((currentScroll - 60) < newScroll && !subHeaderPosition) {
console.log("Scroll position: " + currentScroll);
console.log("Scroll should show Sub-Header");
$("#sub-header").addClass("show");
subHeaderPosition = true;
newScroll = $(window).scrollTop();
} else {
newScroll = $(window).scrollTop();
}
});
#sub-header {
margin-top: 500px;
transition: all .3s;
opacity: 1;
visibility: visible;
}
.hide {
opacity: 0;
visibility: hidden;
}
.show {
opacity: 1 !important;
visibility: visible !important;
}
Or just extract Underscore Throttle as nicholaides mentioned.

Related

Class not always applied when user is at top of the page

I am using the following code to apply different classes to #nav depending if the user scrolls UP, DOWN, or is at the top of the page.
.nav-down applied when user scrolls up
.nav-up applied when user scrolls down
.nav-down-top when user scrolls to the top of the page
code
jQuery(document).ready(function($){
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = $('nav').outerHeight(true);
$(window).scroll(function(event) { didScroll = true; });
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 100);
function hasScrolled() {
if($( window ).width() > 768) {
var st = $(this).scrollTop();
if (Math.abs(lastScrollTop - st) <= delta)
return;
if (st > lastScrollTop) {
// Scroll Down
$('#s-nav').removeClass('nav-down').removeClass('nav-down-top').addClass('nav-up');
} else {
// Scroll Up (# top of screen)
if (st === 0) {
$('#s-nav').removeClass('nav-up').removeClass('nav-down').addClass('nav-down-top');
} else { //if (st + $(window).height() < $(document).height()) {
$('#s-nav').removeClass('nav-up').removeClass('nav-down-top').addClass('nav-down');
}
}
}
lastScrollTop = st;
}
});
The problem is that when the user is at the top of the page or scrolls to the top .nav-down-top doesn't always get applied. This often happens when the user doesn't scroll very far to get to the top. I'm not sure how to ensure that .nav-down-top is applied when the user is at the top of the page.
$(function(){
var shrinkHeader = 300;
$(window).scroll(function() {
var scroll = getCurrentScroll();
if ( scroll >= shrinkHeader ) {
$('.navbar-fixed').addClass('class');
}
else {
$('.navbar-fixed').removeClass('oneclass');
$('.navbar-fixed').addClass('otherclass');
}
});
function getCurrentScroll() {
return window.pageYOffset || document.documentElement.scrollTop;
}
});
Try this script cleaner and tell me if it worked
What you seem to want is this:
var el = $('#test1')
$(window).scroll(function(){
if($(window).scrollTop() > 50){
console.log("addClass")
$(el).addClass('slideUp');
} else {
console.log("removeClass")
$(el).removeClass('slideUp');
}
})
https://jsfiddle.net/m0nz41ep/1/
You do not need to set an interval for the window to check the information, since the scroll is already an event that checks the window whenever you input information. :)
Also, are you doing animations?
You need to tell the CSS file that the divs you want to manipulate will be animated.
-webkit-transition: all 1s; // Chrome
-moz-transition: all 1s; // Mozilla
-o-transition: all 1s; // Opera
transition: all 1s;
If it's just one div add it to the id for the div, if it's multiple, add it to a class and add the class to all of the divs. The rest of the code should do the magic!

Header hiding on scroll positioning

I have included a snippet to show the general idea of what I have right now. The snippet will show a header and if you scroll the header stays the same size until the full height of the header has been scrolled down and then it will go away. Then when you scroll up (when the header gone) the header will show.
The issue I cannot seem to figure out is how to remove the position: fixed from my css and still get the javascript to work. I want the header to scroll down normally (just like Stack overflow's header), however with the ability to still re-appear when scrolling up.
I tried taking out position: fixed and the script broke. I also tried adding position: fixed to the nav-up class...neither change worked.
Does anyone know what I could do to make this work?
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = $('header').outerHeight();
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// Make sure they scroll more than delta
if(Math.abs(lastScrollTop - st) <= delta)
return;
// If they scrolled down and are past the navbar, add class .nav-up.
// This is necessary so you never see what is "behind" the navbar.
if (st > lastScrollTop && st > navbarHeight){
// Scroll Down
$('header').removeClass('nav-down').addClass('nav-up');
} else {
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('header').removeClass('nav-up').addClass('nav-down');
}
}
lastScrollTop = st;
}
html, body {
padding:0;
margin:0;
}
header {
/*background: #2F4F4F;*/
/*background: #53868B;*/
/*background: #35586C;*/
background: #F2F2F2;
height: 120px;
position: fixed;
top: 0;
transition: top 0.2s ease-in-out;
width: 100%;
z-index: 100;
}
.nav-up {
top: -120px;
}
#logo {
padding: 5px 20%;
display: inline-block;
}
#logo img {
height: 110px;
width: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<header class="nav-down">
<div id="logo">
<img src="images/eslich.png" alt="">
</div>
</header>
<br><br><Br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><Br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><Br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><Br><br><br><br><br><br><br><br><br><br><br><br><br>
Update
This is the new jsfiddle using her code https://jsfiddle.net/jz8aa5yz/2/
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = $('header').outerHeight();
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// Make sure they scroll more than delta
if(Math.abs(lastScrollTop - st) <= delta)
return;
// If they scrolled down and are past the navbar, add class .nav-up.
// This is necessary so you never see what is "behind" the navbar.
if (st > lastScrollTop && st > navbarHeight){
// Scroll Down
$('header').removeClass('nav-down').addClass('nav-up');
} else {
if (st < navbarHeight) {
if (st === 0 || st < 50) {
$('header').css('position', 'static');
}
} else {
$('header').css('position', 'fixed');
}
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('header').removeClass('nav-up').addClass('nav-down');
}
}
lastScrollTop = st;
}
`
Old
I'm still testing some javascript, but I wonder if the effect you wanted is something like this? I did a few things different, but the main things were using hide(), css(), slideUp(), slideDown(), and if / else statements. Here's a jsfiddle of the example
<script>
$(document).ready(function () {
var header = $("header");
var lastScrollTop = 0;
$(window).on("scroll", function () {
currentScrollTop = $(this).scrollTop();
if ($("body").scrollTop() > header.outerHeight()) {
if (currentScrollTop > lastScrollTop) {
if (header.css("position") == "fixed") {
header.slideUp();
} else {
header.css({
display: "none",
position: "fixed"
});
}
} else {
header.slideDown();
}
} else {
if (currentScrollTop === 0) {
header.css({
display: "block",
position: "static"
});
}
}
lastScrollTop = currentScrollTop;
});
});
</script>

Hide menu on scroll down and show on scroll up

I made this snippet code to hide menu on scroll down and show on scroll up but I have some issues, when I scroll to top the menu still have fixed position, how I can resolve this problem, Thanks!
JAVSCRIPT :
$(window).bind('scroll', function () {
if ($(window).scrollTop() > 500) {
$('.mainmenu').addClass('nav-down');
}
});
// Hide Header on on scroll down
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = $('.mainmenu').outerHeight();
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 500);
function hasScrolled() {
var st = $(this).scrollTop();
// Make sure they scroll more than delta
if(Math.abs(lastScrollTop - st) <= delta)
return;
// If they scrolled down and are past the navbar, add class .nav-up.
// This is necessary so you never see what is "behind" the navbar.
if (st > lastScrollTop && st > navbarHeight){
// Scroll Down
$('.mainmenu').removeClass('nav-down').addClass('nav-up');
} else {
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('.mainmenu').removeClass('nav-up');
}
}
lastScrollTop = st;
}
CSS :
.mainmenu {
background: #222;
height: 50px;
padding: 0 15px;
width: 80%;
margin: 0 auto;
}
.nav-down{
position: fixed;
top: 0;
transition: top 0.2s ease-in-out;
width: 100%;
}
.nav-up {
top: -50px;
}
Demo : jsfiddle
To you first listener, just add an else statement as follows:
$(window).bind('scroll', function () {
if ($(window).scrollTop() > 150)
$('.mainmenu').addClass('nav-down');
else
$('.mainmenu').removeClass('nav-down');
});
Also note that you don't need a setInterval() for the second listener, see jsfiddle
I tested it and it works fine!!
$(window).bind('scroll', function () {
if ($(window).scrollTop() > 500) {
$('.mainmenu').addClass('nav-down');
}
else
{
$('.mainmenu').removeClass('nav-down');
}
});
Add an else to your scrollTop with a removeClass and you should be fine, I tested it and it works. Here
$(window).bind('scroll', function () {
if ($(window).scrollTop() > 500) {
$('.mainmenu').addClass('nav-down');
}
else
{
$('.mainmenu').removeClass('nav-down');
}
});
Detect nav direction with a variable
var lastscrolltop=0;
jQuery(window).bind('scroll', function () {
if (jQuery(window).scrollTop() > lastscrolltop)
jQuery('.mainmenu').addClass('nav-up');
else
jQuery('.mainmenu').removeClass('nav-up');
lastscrolltop=jQuery(window).scrollTop();
});
and use css transition for a smooth show/hide
.mainmenu {
transition:all 0.5s ;
}
Your way is too much complicated.
You can hide the menu on scroll with a simple transition using jQuery .fadeIn() and fadeOut(), without the need for css.
var lastScrollTop = 0;
$(window).scroll(function(event){
var st = $(this).scrollTop();
if (st > lastScrollTop){
$('.mainmenu').fadeOut('fast');
} else {
$('.mainmenu').fadeIn('fast');
}
lastScrollTop = st;
});

Make script start at the top of a specific div

So I basically want the script to start at the top of "mini" div but can't get it to work right.
#mini {
width: 100%;
padding-top: 300px;}
var tTop = $("#mini").outerHeight(true);
Full script:
$(window).scroll(checkY);
function checkY() {
//save this value so we dont have to call the function everytime
var top = $(window).scrollTop();
$(".title").each(function () {
var target = $(this).closest(".content");
var tTop = $("#mini").outerHeight(true);
var tBottom = target.offset().top + target.outerHeight();
if (top >= tTop && top <= tBottom) {
console.log("Show");
$(this).show();
} else {
console.log("Hide");
$(this).hide();
}
});
}
checkY();
Why not setting the mini style to
position:relative;
and the inner div to
position: absolute;
top:0

Fixed header navigation and scrollTo() next/previous elements

First off I use this code to make the navigation bar always stay fixed;
After adding CSS position absolute:
var yOffset = $("#header").offset().top;
$(window).scroll(function() {
if ($(window).scrollTop() > yOffset) {
$("#header").css({
'top': 0,
'position': 'fixed'
});
} else {
$("#header").css({
'top': yOffset + 'px',
'position': 'absolute'
});
}
});
But now my next/previous key events which used to scroll to next element is not catching the right element position.
here is my code for browsing next/prev element.
// scroll to next post
function scrollToNew () {
scrollTop = $(window).scrollTop();
$('.post').each(function(i, h1){
h1top = $(h1).offset().top;
if (scrollTop < h1top) {
$.scrollTo(h1);
return false;
}
});
}
// scroll to previous post
function scrollToLast () {
scrollTop = $(window).scrollTop();
var scrollToThis = null;
$('.post').each(function(i, h1) {
h1top = $(h1).offset().top;
if (scrollTop > h1top) {
scrollToThis = h1;
} else {
return false;
}
});
if(scrollToThis != null) {
$.scrollTo(scrollToThis);
}
}
I simply used to fire the scrollToNew when key pressed and it was working until I made the fixed navigation (#header) because it stays always on top so the heading of post which user scrolls to, becomes invisible. I do not know how to get around this issue.
Any suggestions are greatly helpful really.
Here is the fix.
I added the height of navigation header into offset. Which is exact 61pixels. Problems solved.
// scroll to next post
function scrollToNew () {
scrollTop = $(window).scrollTop();
$('.post').each(function(i, h1){
h1top = $(h1).offset().top;
if (scrollTop < h1top - 61) {
$.scrollTo(h1, {offset: {left: 0, top: -61}});
return false;
}
});
}
// scroll to previous post
function scrollToLast () {
scrollTop = $(window).scrollTop();
var scrollToThis = null;
$('.post').each(function(i, h1) {
h1top = $(h1).offset().top;
if (scrollTop > h1top - 61) {
scrollToThis = h1;
} else {
return false;
}
});
if(scrollToThis != null) {
$.scrollTo(scrollToThis, {offset: {left: 0, top: -61}});
}
}

Categories