jquery: animate down navigation, not sliding back up/working properly - javascript

Hey so i was trying to get my navigation to animate down after a certain div has passed but its not working properly. not sure why. it works when sliding down although a bit buggy(sometimes there seems to be a delay before it slides down and other times it slides down properly immediately). It also does not slide up it justs removes it self.
what am i doing wrong?
here is my code:
$(window).scroll(function () {
targetScroll = $('#scroll_verder').position().top,
currentScroll = $('html').scrollTop() || $('body').scrollTop();
if(currentScroll>=targetScroll){
$('.navbar').addClass('show-menu').animate({ top: '0px' });
}
else {
$('.navbar').stop();
$('.navbar').removeClass('show-menu');
$('.navbar').animate({ top: '-50px' });
}
});

Had a look at your code on the link you posted. This should do the trick:
var reachedTarget = false; // Prevent animation collisions with this
var targetScroll = $('#scroll_verder').position().top;
$(window).scroll(function () {
var currentScroll = $('html').scrollTop() || $('body').scrollTop();
if ( currentScroll >= targetScroll ) {
if ( !reachedTarget ) {
$('.navbar').stop();
$('.navbar').addClass('show-menu').animate({ top: '0px' });
}
reachedTarget = true;
} else{
if ( reachedTarget ) {
$('.navbar').stop();
$('.navbar').removeClass('show-menu').animate({ top: '-50px' });
}
reachedTarget = false;
}
});
EDIT: In CSS (to make sure initial position is correct):
.navbar.show-menu {
z-index: 999;
display: block;
top : -50px;
}

Related

Add and Remove class on window scroll [duplicate]

So basically I'd like to remove the class from 'header' after the user scrolls down a little and add another class to change it's look.
Trying to figure out the simplest way of doing this but I can't make it work.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll <= 500) {
$(".clearheader").removeClass("clearHeader").addClass("darkHeader");
}
}
CSS
.clearHeader{
height: 200px;
background-color: rgba(107,107,107,0.66);
position: fixed;
top:200;
width: 100%;
}
.darkHeader { height: 100px; }
.wrapper {
height:2000px;
}
HTML
<header class="clearHeader"> </header>
<div class="wrapper"> </div>
I'm sure I'm doing something very elementary wrong.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
//>=, not <=
if (scroll >= 500) {
//clearHeader, not clearheader - caps H
$(".clearHeader").addClass("darkHeader");
}
}); //missing );
Fiddle
Also, by removing the clearHeader class, you're removing the position:fixed; from the element as well as the ability of re-selecting it through the $(".clearHeader") selector. I'd suggest not removing that class and adding a new CSS class on top of it for styling purposes.
And if you want to "reset" the class addition when the users scrolls back up:
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 500) {
$(".clearHeader").addClass("darkHeader");
} else {
$(".clearHeader").removeClass("darkHeader");
}
});
Fiddle
edit: Here's version caching the header selector - better performance as it won't query the DOM every time you scroll and you can safely remove/add any class to the header element without losing the reference:
$(function() {
//caches a jQuery object containing the header element
var header = $(".clearHeader");
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 500) {
header.removeClass('clearHeader').addClass("darkHeader");
} else {
header.removeClass("darkHeader").addClass('clearHeader');
}
});
});
Fiddle
Pure javascript
Here's javascript-only example of handling classes during scrolling.
const navbar = document.getElementById('navbar')
// OnScroll event handler
const onScroll = () => {
// Get scroll value
const scroll = document.documentElement.scrollTop
// If scroll value is more than 0 - add class
if (scroll > 0) {
navbar.classList.add("scrolled");
} else {
navbar.classList.remove("scrolled")
}
}
// Use the function
window.addEventListener('scroll', onScroll)
#navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 60px;
background-color: #89d0f7;
box-shadow: 0px 5px 0px rgba(0, 0, 0, 0);
transition: box-shadow 500ms;
}
#navbar.scrolled {
box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.25);
}
#content {
height: 3000px;
margin-top: 60px;
}
<!-- Optional - lodash library, used for throttlin onScroll handler-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
<header id="navbar"></header>
<div id="content"></div>
Some improvements
You'd probably want to throttle handling scroll events, more so as handler logic gets more complex, in that case throttle from lodash lib comes in handy.
And if you're doing spa, keep in mind that you need to clear event listeners with removeEventListener once they're not needed (eg during onDestroy lifecycle hook of your component, like destroyed() for Vue, or maybe return function of useEffect hook for React).
Example throttling with lodash:
// Throttling onScroll handler at 100ms with lodash
const throttledOnScroll = _.throttle(onScroll, 100, {})
// Use
window.addEventListener('scroll', throttledOnScroll)
Add some transition effect to it if you like:
http://jsbin.com/boreme/17/edit?html,css,js
.clearHeader {
height:50px;
background:lightblue;
position:fixed;
top:0;
left:0;
width:100%;
-webkit-transition: background 2s; /* For Safari 3.1 to 6.0 */
transition: background 2s;
}
.clearHeader.darkHeader {
background:#000;
}
Its my code
jQuery(document).ready(function(e) {
var WindowHeight = jQuery(window).height();
var load_element = 0;
//position of element
var scroll_position = jQuery('.product-bottom').offset().top;
var screen_height = jQuery(window).height();
var activation_offset = 0;
var max_scroll_height = jQuery('body').height() + screen_height;
var scroll_activation_point = scroll_position - (screen_height * activation_offset);
jQuery(window).on('scroll', function(e) {
var y_scroll_pos = window.pageYOffset;
var element_in_view = y_scroll_pos > scroll_activation_point;
var has_reached_bottom_of_page = max_scroll_height <= y_scroll_pos && !element_in_view;
if (element_in_view || has_reached_bottom_of_page) {
jQuery('.product-bottom').addClass("change");
} else {
jQuery('.product-bottom').removeClass("change");
}
});
});
Its working Fine
Is this value intended? if (scroll <= 500) { ... This means it's happening from 0 to 500, and not 500 and greater. In the original post you said "after the user scrolls down a little"
In a similar case, I wanted to avoid always calling addClass or removeClass due to performance issues. I've split the scroll handler function into two individual functions, used according to the current state. I also added a debounce functionality according to this article: https://developers.google.com/web/fundamentals/performance/rendering/debounce-your-input-handlers
var $header = jQuery( ".clearHeader" );
var appScroll = appScrollForward;
var appScrollPosition = 0;
var scheduledAnimationFrame = false;
function appScrollReverse() {
scheduledAnimationFrame = false;
if ( appScrollPosition > 500 )
return;
$header.removeClass( "darkHeader" );
appScroll = appScrollForward;
}
function appScrollForward() {
scheduledAnimationFrame = false;
if ( appScrollPosition < 500 )
return;
$header.addClass( "darkHeader" );
appScroll = appScrollReverse;
}
function appScrollHandler() {
appScrollPosition = window.pageYOffset;
if ( scheduledAnimationFrame )
return;
scheduledAnimationFrame = true;
requestAnimationFrame( appScroll );
}
jQuery( window ).scroll( appScrollHandler );
Maybe someone finds this helpful.
For Android mobile $(window).scroll(function() and $(document).scroll(function() may or may not work. So instead use the following.
jQuery(document.body).scroll(function() {
var scroll = jQuery(document.body).scrollTop();
if (scroll >= 300) {
//alert();
header.addClass("sticky");
} else {
header.removeClass('sticky');
}
});
This code worked for me. Hope it will help you.
This is based of of #shahzad-yousuf's answer, but I only needed to compress a menu when the user scrolled down. I used the reference point of the top container rolling "off screen" to initiate the "squish"
<script type="text/javascript">
$(document).ready(function (e) {
//position of element
var scroll_position = $('div.mainContainer').offset().top;
var scroll_activation_point = scroll_position;
$(window).on('scroll', function (e) {
var y_scroll_pos = window.pageYOffset;
var element_in_view = scroll_activation_point < y_scroll_pos;
if (element_in_view) {
$('body').addClass("toolbar-compressed ");
$('div.toolbar').addClass("toolbar-compressed ");
} else {
$('body').removeClass("toolbar-compressed ");
$('div.toolbar').removeClass("toolbar-compressed ");
}
});
}); </script>

Offset Top Not Working In IOS

Here is the complete code http://jsfiddle.net/vinex08/uhm26em1/
jQuery(function ($) {
var distance = $('.c').offset().top,
$window = $(window);
$window.scroll(function () {
if ($window.scrollTop() >= distance) {
$(".b").css({
position: 'fixed',
top: '0'
});
} else {
$(".b").css({
position: 'inherit',
top: '10'
});
}
});
});`
It's working on Chrome and Firefox but when i checked it via iPad AIR and iPhone, the effect executes even before the 'class c' hits the top.
I hope this will help:
jQuery(function ($) {
var distance = $('.c').offset().top;
$(window).scroll(function () {
var wndwTop = $(this).scrollTop();
if (wndwTop >= distance) {
$(".b").css({
position: 'fixed',
top: '0'
});
} else {
$(".b").css({
position: 'inherit',
top: '10'
});
}
});
});
Here we have known fix for mobile Safari.
Firstly, detect browser; secondly, a little bit change behavior of the 'offset' function:
// mobile Safari reports wrong values on offset()
// http://dev.jquery.com/ticket/6446
if ( /webkit.*mobile/i.test(navigator.userAgent)) {
(function($) {
$.fn.offsetOld = $.fn.offset;
$.fn.offset = function() {
var result = this.offsetOld();
result.top -= window.scrollY;
result.left -= window.scrollX;
return result;
};
})(jQuery);
}
Place this code somewhere after jquery initialization, but before your offset computations.

scroll to next div already in browser

I have a series of divs that are 100% height with a scroll to function that takes you to the next div out of the viewport on background click. However, if the next div is already slightly in the viewport the whole thing is counted as being visible and the scroll to bypasses it. Can anyone offer direction on how to get the script to scroll to the div even if it's partially in the viewport already?
Codepen here.
If you begin scrolling slightly in the codepen and then click on the background you'll see that it doesnt scroll you to the div that's already in the viewport but the div after that.
$(document).ready(function() {
// get initial nav height
var $window = $(window);
var wst = $window.scrollTop();
var th = $('div.top').height();
var currentSlide = $('#wrapper').data( 'current-slide', $('div.slide').eq(0) );
$('div.scroll_images').css({ height: 'auto', overflow: 'visible', top: 0 });
$('div.scroll_images div.inner').css({ position: 'absolute', top: 0 });
$('div.slide').each(function() {
$(this).css('padding',function() {
return (($(window).height()-$(this).height())/2)+'px 0'
});
});
// scrollto for click on slide
jQuery.fn.scrollTo = function(hash) {
$this = $(this);
st = $this.offset().top - th; // subtract nav height
$('html, body').animate({ scrollTop: st }, 550
);
}
$('#wrapper').click(function(e){
//get the current slide index from the body tag.
$this = currentSlide.data( 'current-slide' );
$next = $(".slide:below-the-fold");
if($next.length) {
$next.scrollTo($next.attr('id'));
//Save the next slide as the current.
$('#wrapper').data( 'current-slide', $next );
} else {
//Throw us back to the top.
$('div.slide:first').scrollTo($('div.slide:first').attr('id'));
//Save the first slide as the first slide, which
//Cycles us back to the top.
$('#wrapper').data( 'current-slide', $('div.slide:first'));
}
})
//Images fade in
$('img').hide();
$('img').each(function(i) {
if (this.complete) {
$(this).fadeIn();
} else {
$(this).load(function() {
$(this).fadeIn();
});
}
});
//Stop links affecting scroll function
$("a").click(function(e) {
e.stopPropagation();
});
});
(function($) {
$.belowthefold = function(element, settings) {
var fold = $(window).height() + $(window).scrollTop();
return fold <= $(element).offset().top - settings.threshold;
};
$.extend($.expr[':'], {
"below-the-fold": function(a, i, m) {
return $.belowthefold(a, {threshold : 0});
}
});
})(jQuery);
Here's what I might try to do: go through each div in the series. Find the div who's offset() is closest to $(window).scrollTop(). Now, find the next() div after the "current" one and scroll to it.
For comparing the offset() of each div, try something like this:
var closest = $('[selector]:first');
$('[selector]').each(function() {
var oldDistance = Math.abs(closest.offset() - $(window).scrollTop());
var newDistance = Math.abs($(this).offset() - $(window).scrollTop());
if(newDistance < oldDistance) {
closest = $(this);
}
}

Javascript scroll doesn't stop

hi everyone i'm trying to do simple scroll share box widget but it doesn't work. It must stop on special div (stopscroll), but it don't stop and scrolling down until web page footer. any ideas why?
var windw = this;
$.fn.followTo = function ( elem ) {
var $this = this,
$window = $(windw),
$bumper = $(elem),
bumperPos = $bumper.offset().top,
thisHeight = $this.outerHeight(),
setPosition = function(){
if ($window.scrollTop() <= (bumperPos - thisHeight)) {
$this.css({
position: 'absolute',
top: (bumperPos - thisHeight)
});
} else {
$this.css({
position: 'fixed',
top: 0
});
}
};
$window.resize(function()
{
bumperPos = pos.offset().top;
thisHeight = $this.outerHeight();
setPosition();
});
$window.scroll(setPosition);
setPosition();
};
$('#share_box').followTo('#stopscroll');
but it doesn't stop on the div #stopscroll.
css file looks like that:
#share_box{
background: none repeat scroll 0% 0% #E1E1E1;
position: fixed;
width: 65px;
padding: 15px;
border-radius: 5px 0px 0px 5px;
left: 1.89%;}
any ideas?
here is jsfiddle http://jsfiddle.net/NCY6x/
There are lots of syntax and variable mistakes in your code...
I have updated the fiddle with a working and simpler demo: http://jsfiddle.net/NCY6x/2/
$.fn.followTo = function ( elem ) {
var stopper = $(elem);
var box = this;
$(window).on("scroll resize", function(){
var x_distance = (stopper.offset().top- box.outerHeight());
if($(window).scrollTop() >= x_distance){
box.css({"position": "absolute", "top": x_distance});
} else {
box.css({"position": "fixed", "top": 0});
}
});
};
$('#share_box').followTo('#stopscroll');
Well, in your Fiddle you haven't actually loaded jQuery, and then when loaded I get an error saying pos is not defined, which I think refers to the following line:
bumperPos = pos.offset().top;
pos doesn't appear to be set anywhere
Edit:
There were some other issues with your script. See here for a version that I think works as you intend http://jsfiddle.net/R5z6j/1/
I removed the padding on the top of #stopscroll as that doesn't move the element down so the top position was always being set to 18px (see the console output)
Edit 2:
http://jsfiddle.net/R5z6j/5/ - as you'll probably actually want it this way round

Convert click code to hover code

How can I change the following menu code to open/close when the mouse hovers, instead of when it is clicked on?
var w = 0;
$('.slide').children().each(function () {
w += $(this).outerWidth();
});
$('.outer').width(w + 5);
$('.wrap').width(w);
$('.slide').css('left', w);
$('.open').toggle(function () {
$('.slide').stop().animate({
left: 0
});
$(this).html('close');
}, function () {
$('.slide').stop().animate({
left: w
});
$(this).html('open');
});
Please check this Demo
In Fiddle, you can see the animation works on click. I need to make it work on hover. Can you help with this ?
Use .hover() api
Try this
$('.open').hover(function () {
instead of
$('.open').toggle(function () {
Just
$('.open').toggle(function() {
$('.slide').stop().animate({
left: 0
});
$(this).html('close');
}
in this part just replace toggle with hover
Try using $('.wrap').hover. If $('.open').hover, you will not able to click the nav items.
Also, you can create another wrapper to just wrap div.outer and a.open only
$('.wrap').hover(function() {
$('.slide').stop().animate({
left : 0
});
//this is the .wrap right now
$(this).find('a.open').html('close');
}, function() {
$('.slide').stop().animate({
left : w
});
//this is the .wrap right now
$(this).find('a.open').html('open');
});
http://jsfiddle.net/rooseve/42sWB/2/
$('.open').on('mouseenter mouseleave', function(e) {
if(e.type === 'mouseleave') {
$('.slide').stop().animate({
left: w
});
$(this).html('open');
} else {
$('.slide').stop().animate({
left: 0
});
$(this).html('close');
}
});
var w = 0;
var isVisible = false;
$('.slide').children().each(function() {
w += $(this).outerWidth();
});
$('.outer').width(w+5);
$('.wrap').width(w);
$('.slide').css('left', w);
$('.open').on("mouseover", function() {
if(isVisible == false) {
$('.slide').stop().animate({
left: 0
});
$(this).html('close');
isVisible = true;
}
else {
$('.slide').stop().animate({
left: w
});
$(this).html('open');
isVisible = false;
}
});
Firstly, when you hover the element - the div will be visible, until you hover the element for the second time.
Demo: http://jsfiddle.net/42sWB/3/

Categories