Nav Shrink on Scroll or Resize - javascript

I'm trying to apply a series of classes to a nav that cause it to shrink if the window is either resized or scrolled passed a certain point. However, I believe my conditions are cancelling each other out, and I'm not sure how to structure the if-statements or if it is better to just pass a variable.
Here's what I am trying to accomplish:
If the window is resized between a certain set of media queries, shrink the nav
If the window is outside of those break-points, and the user scrolls passed 1 (I used one just for example purposes in my code so I could see it right away) the nav will shrink and if they scroll up again, it will become it's full size
My code is here:
$(document).ready(function() {
var logo = $('.logo');
var topLevelListItems = $('.mainNav li');
var navShrink = false;
var mQ = window.matchMedia( '(min-width: 100px) and (max-width: 770px)' );
$(window).resize(function() {
if ( mQ.matches ) {
$('nav').addClass('shrink');
$('.nav-fixedWidth').addClass('shrink');
logo.addClass('shrink');
topLevelListItems.addClass('shrink');
navShrink = true;
}
else{
$('nav').removeClass('shrink');
$('.nav-fixedWidth').removeClass('shrink');
logo.removeClass('shrink');
topLevelListItems.removeClass('shrink');
navShrink = false;
}
});//end of resize function
$(window).onscroll(function(){
if( !(mQ.match) && $(this).scrollTop >= 1 ) {
$('nav').addClass('shrink');
$('.nav-fixedWidth').addClass('shrink');
logo.addClass('shrink');
topLevelListItems.addClass('shrink');
navShrink = true;
} else {
$('nav').removeClass('shrink');
$('.nav-fixedWidth').removeClass('shrink');
logo.removeClass('shrink');
topLevelListItems.removeClass('shrink');
navShrink = false;
}
});//end of scroll function
});//end of doc

Could it simply be a typo in your onscroll function?
i.e you have:
if( !(mQ.match) && $(this).scrollTop >= 1 ) { ...
should it not be:
if( !(mQ.matches) && $(this).scrollTop >= 1 ) { ...

Related

Do something once in $(window).scroll function during multiple conditional statements

This is throwing me for a loop..
The basic idea is we're using $(window).scroll() and as you scroll down the page, when an element is in view by using offset() with scrollTop "do something" then when you hit the next element down the page "do something more".
However, because the scroll event (probably the wrong term) fires every single time in the conditional statement because technically the statement is true every scroll, I need it to only fire once, but then be able to 're-fire again' one time when the next conditional happens.
$(window).scroll(function(){
let windowTop = $(window).scrollTop()
if( windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top ) {
doSomething(); // want this to only fire once
} else if( windowTop > $('.element2').offset().top ) {
doSomething(); // want this to only fire once
}
});
I had a theory about possibly setting a variable to true so it only fire's doSomething() once, but then when it's inside the 2nd conditional statement I can't wrap my head around undoing / resetting it.
let fired = false;
$(window).scroll(function(){
let windowTop = $(window).scrollTop()
if( windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top ) {
if(!fired){
doSomething();
fired = true;
}
} else if( windowTop > $('.element2').offset().top ) {
// need to somehow set fired to false again so it triggers once then sets back to true
if(!fired){
doSomething();
fired = true;
}
}
});
Hope I somehow made sense!
Consider the following.
var fire = {
"element1": true,
"element2": true
};
$(window).scroll(function(event){
var windowTop = $(window).scrollTop();
console.log("Window Scroll Top: " + windowTop);
if( fire.element1 && (windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top) ) {
console.log("Do Something!", $('.element').offset().top);
fire.element1 = false;
doSomething();
} else if( fire.element2 && (windowTop > $('.element2').offset().top) ) {
console.log("Do Something!", $('.element2').offset().top);
fire.element2 = false;
doSomething();
}
});
The logic here is we check if we should fire the event for each element. In this way we have a more complex IF condition. Fire for that element must be true and the Scroll position must have gone down far enough.
If the Top of the element is 100, this condition should only be true at one time and one time only, when windowTop is a value of 101 or higher. Now if you want it to trigger when the element is fully in view, you need the Top plus the Height. If it's 40px tall, then it would be 140 (Top + Height).

Scrolling Add Class Over Value Only Once

I stumbled upon an issue with a menu that I want to open by adding a "Open" class when scrolled above certain value. The issue is that I want it to open only ONCE after that value so it appears for the user, and then is up to the user to open and close it by a toggle.
I used this method:
<script type="text/javascript">
jQuery(function() {
//caches a jQuery object containing the header element
jQuery(window).scroll(function() {
var scroll = jQuery(window).scrollTop();
if (scroll >= 1150) {
jQuery(".menubar").addClass("open");
}
});
});
</script>
The issue is that after the 1150 value, it keeps poping up after every scroll within this value.
How do I make it stop and make this event happen only once?
Thank you in advance!
Check if the class is already existing. Or use a variable if the class changes too easily:
var isOpened = false;
jQuery(function() {
//caches a jQuery object containing the header element
jQuery(window).scroll(function() {
var scroll = jQuery(window).scrollTop();
// The original if statement, testing for `.hasClass()`
// if (scroll >= 1150 && !$(".menubar").hasClass()) {
if (scroll >= 1150 && !isOpened) {
isOpened = true;
jQuery(".menubar").addClass("open");
}
});
});
You can set a flag and then just check against that flag.
jQuery(function() {
var menuBarOpenedOnce = 0;
//caches a jQuery object containing the header element
jQuery(window).scroll(function() {
var scroll = jQuery(window).scrollTop();
if (scroll >= 1150 && menuBarOpenedOnce === 0) {
jQuery(".menubar").addClass("open");
menuBarOpenedOnce = 1;
}
});
});

Restore scroll position after mobile menu is closed

I'm having a mobile menu that opens and closes using jquery by adding a css class that has display:block while the menu div has display:none.
The jquery code has a part where it is supposed to close the menu when a click is registered outside the menu div. Everything works execept the: $("body").scrollTop(scrollpos) . This was supposed to scroll the user back where he left off after the scrollTop(0) took place and the menu has closed, but it does not scroll at all the scroll is stuck at the top. Any help will be appreciated. Thank you.
EDIT: Here is an example: https://jsfiddle.net/mufwwudj/
$(function () {
var menutoggle = $(".menu-toggle");
var sidenav = $(".side-nav");
menutoggle.click(function () {
var scrollpos = $('body').scrollTop();
if (!$("body").hasClass("m-nav-open")) {
$("body").scrollTop(0).addClass("m-nav-open");
}
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
});
});
One problem here is that you are assigning a new mouseup event every time the menutoggle.click function runs.
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
Only the first one passes the conditional, even though each one will fire and scrollpos will always equal whatever it was in the first mouseup event listener.
I don't know how you are testing it, or what the HTML looks like but if you are at the top of the page the first time you click it, scrollpos in the mouseup event will always be 0.
Try assigning the mouseup event once, and putting scrollpos outside both so it can be accessed in both.
$(function () {
var menutoggle = $(".menu-toggle");
var sidenav = $(".side-nav");
var scrollpos;
menutoggle.click(function () {
scrollpos = $('body').scrollTop();
if (!$("body").hasClass("m-nav-open")) {
$("body").scrollTop(0).addClass("m-nav-open");
}
});
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
});
function ScrollOnTopo() {
window.scrollTo(0, 0); //It scrolls page at top
}
This function may be useful to you.

jQuery to top function disallows scrolling

I'm creating magento shop and i want to make toTop button available after user scrolls the window.
I paste mine code bellow, it works fine, but after window is on top, i can't move it anymore, it's stuck.
jQuery(window).scroll(function() {
var top = jQuery(window).scrollTop();
if (top > 77) {
jQuery(function() {
jQuery('img.arrowup').fadeIn();
jQuery('div.header_bg').show();
jQuery('div.mainmenu').addClass('stick');
jQuery('body div.header-container').next().addClass('pad');
jQuery("img.arrowup").on('click', function(e) {
e.preventDefault();
jQuery('body,html').animate({scrollTop:10},800);
});
})} else {
jQuery('div.header_bg').hide();
jQuery('img.arrowup').fadeOut();
jQuery('body div.header-container').next().removeClass('pad');
jQuery('div.mainmenu').removeClass('stick');
}
});
============================
Thanks everybody for help, here's working solution with stick header and toTop animation :)
var scrollDiv=jQuery(this);
jQuery(window).scroll(function(){
if(jQuery(window).scrollTop()<="77"){
jQuery("img.arrowup").fadeOut("slow");
jQuery('div.header_bg').hide();
jQuery('div.mainmenu').removeClass('stick');
} else {
jQuery("img.arrowup").fadeIn("slow");
jQuery('div.header_bg').show();
jQuery('div.mainmenu').addClass('stick');
}
});
jQuery("img.arrowup").click(function(){
jQuery("html, body").animate({scrollTop:0},"slow");
});
I suggest to read this answer first for understanding why animations creates conflict depends on scroll value, than give it a try to this:
$(document).ready(function() {
$(window).scroll(function() {
var scrollVal = $(this).scrollTop(); // use this instead of window
if ( scrollVal >= 0 && scrollVal < 77 ) {
//do something without animations
$('div.header_bg').hide();
$('div.mainmenu').removeClass('stick');
} else if ( scrollVal === 77 ){
//i didn't try this before but it may work,
//since value equals 77 once, it may not create animation conflicts
$('img.arrowup').fadeIn();
} else if ( scrollVal > 77 ) {
//do something without animations
$('div.header_bg').show();
$('div.mainmenu').addClass('stick');
}
});
});

Basic Js function to scale two DIV's heights

I want #result to being scaled to #sidebar height if set. If not, leaving #result at its original height.
My code:
window.onload = setDiv;
function setDiv() {
var e = document.getElementById('sidebar'); // Get the sidebar infos
var eh = e.offsetHeight // div height
if ( typeof(eh) == "undefined" || typeof(eh) == null) { // if sidebar isnt in the page
alert(eh);
return true;
} else {
var eh = e.offsetHeight // div height
var d = document.getElementById('result') // Get the result div height
var dh = d.offsetHeight // div height
d.style.height = eh + 65 + 'px'; // Set result div height to sidebar height
alert(d);
document.write(dh);
return false;
}
}
I don't think HTML/CSS is needed.
Thank you.
This line seems wrong:
if ( typeof(eh) == "undefined" || "null") { // if sidebar isnt in the page
try this:
if ( typeof(eh) == "undefined" || typeof(eh) == null) { // if sidebar isnt in the page
Also, I would add in a try catch block. If there is a throw you won't even know your code did not execute.
This causes an error because e does not exist (yet):
var e = document.getElementById('sidebar'); // <<< This is what doesn't work
This is because your window.onload is not done right. Take the parentheses off:
window.onload = setDiv;
http://jsfiddle.net/userdude/u8DZx/3/
I want to demonstrate how easy this is to do in a library like jQuery. window.onload does not always work the way you think either; it's often better to use onDomReady, or $(document).ready() in jQuery. You can also add multiple handlers at different points in the page load, which is more difficult just using the window.onload method.
$(document).ready(function(){
setTimeout(function(){setDiv();},2000); // So you can see the transition
});
function setDiv() {
var $sidebar = $('#sidebar');
if ($sidebar.size() === 0) {
return true;
} else {
$('#result').animate({
height : $('#sidebar').height()
}, 5000);
return false;
}
}
http://jsfiddle.net/userdude/u8DZx/1/
If you don't want the effect, just do:
$('#result').height($('#sidebar').height());
And if you actually meant to use offsetHeight, which it doesn't sound like that's what you want (height instead), you could do this:
$(document).ready(function(){
setTimeout(function(){setDiv();},2000); // So you can see the transition
});
function setDiv() {
var $sidebar = $('#sidebar');
if ($sidebar.size() === 0) {
return true;
} else {
$('#result').offset($('#sidebar').offset());
return false;
}
}
http://jsfiddle.net/userdude/u8DZx/2/

Categories