I have a website with two scroll options. When you scroll down, it scrolls to the anchor Point 1.
I also have a Button which jumps to the same anchor point.
My problem: When I click the Button, the site jumps to the Anchor, but because there are two ways to the anchor, it triggers the first scroll option as well.
jQuery(document).ready(function($) {
var flag = true;
$(window).scroll(function () {
if (flag == true) {
scroll = $(window).scrollTop();
if (scroll > 50) $('#scroll-down')[0].click();
flag = false;
}
});
$(window).scroll(function () {
if (flag == false) {
scroll = $(window).scrollTop();
if (scroll < 50 )
flag = true;
}
});
});
Any solutions for this ?
From the screencast you sent, this code should scroll to the bottom of the banner when the button is clicked (provided you correctly place the anchor div):
jQuery(document).ready(function ($) {
// The button is assumed to have an id of 'scroll-down' - triggered when clicked
$('#scroll-down').on('click', function () {
// Move to the pre-defined anchor point
// Insert <div id="scroll-down-anchor"></div> to where you want to scroll to
$('html, body').animate({
scrollTop: $('[id=scroll-down-anchor]').position().top
// Set the speed of the scroll here (currently set to 1000 ms)
}, 1000);
});
});
I'm still not sure from the screencast what you want to do with the behaviour based on the window position when the window is scrolled.
UPDATE: In light of the screencast and further information.
The code has been updated, BUT, although this is, I think, what your code was trying to achieve, I don't think the effect is very nice at all because you're intercepting a user's intention, hijacking it, and making something different happen. It's also very choppy, and to improve that would probably take many more lines of code (eg to determine speed of existing scroll, intercept that and make it accelerate organically - way beyond the scope of this kind of answer). Maybe there's a plugin out there to do this nicely.
Anyway, I think this code completes what you were trying to achieve, but the end effect, although subjective, is not very nice in my opinion. I've put in explanatory comments:
jQuery(document).ready(function ($) {
// Variable to store scrolling state
var scrolling = false;
// Variable to store position to determine whether scrolling up or scrolling down
var previousScroll = 0;
$(window).scroll(function () {
// Only is state is not 'scrolling' (ie not to run if button has been clicked)
if (scrolling === false) {
// Get position
var currentScroll = $(this).scrollTop();
// Compare position to stored variable: scrolling up or scrolling down
if (currentScroll > previousScroll) {
// Determine if position is 'within the zone' - set here to 50px
if (currentScroll < 50 && currentScroll !== 0) {
console.log('IN ZONE');
// Trigger button click
$('#scroll-down').trigger('click');
} else {
// Normal scrolling down code, outside zone
console.log('SCROLLING DOWN ');
}
}
else {
// Scrolling up code
console.log('SCROLLING UP ');
}
// Set variable for comparison of next scroll event
previousScroll = currentScroll;
}
});
// The button is assumed to have an id of 'scroll-down' - triggered when clicked
$('#scroll-down').on('click', function () {
// Set the scrolling state
scrolling = true;
// Animate with callback to set scrolling back to 'true' when complete
$('html, body').animate({ scrollTop: $('[id=scroll-down-anchor]').position().top }, 1000, function () {
// Callback code - set scrolling state to be false when animation has finished
scrolling = false;
});
});
});
Related
I'm trying to trigger a smooth scroll to an element at the end of the page and another one to the top of the page everytime I move the mousewheel respectively down or up. The two parts have both height:100vh.
The thing is that once it goes down it starts to behave randomly.
I feel like I need to interrupt the animation completely after the scroll is completed because it "fights with itself" struggling to go back up and vice versa. Of course I could be easiy wrong, I'm trying to learn the way.
Is there some performance issue? Maybe it is unable to get the inputs in time? Something is overlapping? It seems like there's some sort of cooldown before I can scroll again. This is what I'm trying to understand. Thanks
jQuery(window).bind('mousewheel DOMMouseScroll', function(event){
if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
// scroll up
console.log("scroll up");
jQuery('html,body').animate({scrollTop: jQuery("#top").offset().top}, 1200, 'linear');
}
else {
// scroll down
console.log("scroll down");
jQuery('html,body').animate({scrollTop: jQuery("#bottom").offset().top}, 1200, 'linear');
}
});
Same thing with this, here I'm using the Jquery.scrollTo library
jQuery(window).bind('mousewheel DOMMouseScroll', function(event){
if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
// scroll up
console.log("scroll up");
jQuery('body').scrollTo('#top', {duration:1200});
}
else {
// scroll down
console.log("scroll down");
jQuery('body').scrollTo('#bottom', {duration:1200});
}
});
Here's the html for completeness:
<div id="top" style="height:100vh;background-color: #2196f3;"></div>
<div id="bottom" style="height:100vh;background-color: #009688;"></div>
EDIT:
If I move the mousewheel just the bare minimum it works perfectly both ways so the problem is input overlapping, in other words I need a way to send just the first scroll input and not the entire scroll otherwise too many inputs make the script "crash".
here's a working example, try to scroll up and down:
https://jsfiddle.net/mr8hnxbd/
Calling .stop(true) works, but I believe it might cause issues mid animation if you keep scrolling in the direction of the animation, extending the duration of the animation. Alternatively you can do the following to ensure the animation completes before doing another animation.
(function(jQuery) {
let position = '';
let scrolling = false;
let animationDuration = 1200;
jQuery(window).bind('mousewheel', function(event){
if (event.originalEvent.wheelDelta > 0) {
// scroll up
if (scrolling || position === 'top')
return;
//console.log("scroll up");
scrolling = true; //Prevents any scrolling when scrolling is active
position = 'top'; //Prevents scrolling up when already at the top
jQuery('html,body').animate(
{
scrollTop: jQuery("#top").offset().top
},
animationDuration,
'linear',
function () {
scrolling = false; //After the animation is complete, set scroling to false
},
);
}
else {
// scroll down
if (scrolling || position === 'bottom')
return;
//console.log("scroll down");
scrolling = true;
position = 'bottom';
jQuery('html,body').animate(
{
scrollTop: jQuery("#bottom").offset().top
},
animationDuration,
'linear',
function () {
scrolling = false;
},
);
}
});
})($);
<div id="top" style="height:100vh;background-color: #2196f3;"></div>
<div id="bottom" style="height:100vh;background-color: #009688;"></div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
I know there are many similar posts, but still I haven't get to the code I need.
Basically, I want to make a presentation the first time the user scrolls down. For that, I want to prevent the default action of scroll and (if it's scrolling down) make an animation to the next div.
window.scrolledToRed = false
window.scrolledToGreen = false
window.scrollTo = (to, guard ) =>
$('html, body').animate({
scrollTop: $(to).offset().top
}, 1000, =>
window[guard] = true
)
window.addEventListener 'wheel', (e) ->
if (e.wheelDelta < 0)
if (!window.scrolledToRed)
scrollTo('.red', 'scrolledToRed')
else if (!window.scrolledToYellow)
scrollTo('.green', 'scrolledToGreen')
I've created a Fiddle that represents the problem:
https://jsfiddle.net/pn6zqgwu/2/
When the user scrolls down the first time I want to take him to the red div and the next time to the green one.
None of the solutions I've tried really worked, since it was both "jumping" and scrolling where I want.
Any idea of how to solve the problem?
Thanks in advanced
Maybe you need to call e.preventDefault() to prevent browser default scroll behavior
I have made a fiddle for you, you can make more checks and add animations
var redTouched = false;
var greenTouched = false;
function scrollCb() {
event.preventDefault();
console.log(event.wheelDelta)
if (event.wheelDelta < 0) {
if (!redTouched) {
$(window).scrollTop($('.red').position().top);
redTouched = true;
} else if (redTouched && !greenTouched) {
$(window).scrollTop($('.green').position().top);
greenTouched = true;
} else if (redTouched && greenTouched) {
window.removeEventListener('mousewheel', scrollCb)
}
} else {
window.removeEventListener('mousewheel', scrollCb)
}
window.addEventListener('mousewheel', scrollCb);
https://jsfiddle.net/jacobjuul/b0k03wtr/
I have a problem with the scrolling animation. Jumpy scroll occurs when the page is scrolled after scroll-animation. I suspected the scroll-event repeats itself, but I'm not sure. Can you help me with it?
$(document).ready(function(){
var offset;
var anchor = $("#navigation").offset().top;
$(window).bind('mousewheel', function (e) {
offset = $(window).scrollTop();
if (e.originalEvent.wheelDelta < 0) {
//mouse scroll down
console.log('Down: ' + offset + " " + anchor);
if (offset >= anchor) {
// if anchor has been scrolled, user can scroll further
// the problem ocuurs in this block
return true;
} else {
// animate to anchor( nav menu)
$("body, html").animate({
scrollTop: anchor + 1
}, 200);
$("#navigation").addClass("nav-fixed");
return false;
}
} else {
//mouse scroll up
if (offset < anchor) {
$("#navigation").removeClass("nav-fixed");
return true;
}
}});
});
JSFiddle: http://jsfiddle.net/0noms3cs/
Thank you a lot!
Your issue is simple. The scroll event fires over and over again. Your line of thinking behind the cause of this issue is correct, you have a large number of animate events that get stacked up which causes this weird behavior.
You can resolve this issue by adding a boolean variable (such as scrollInitialized) that starts out as false and gets flipped to true once the scroll event has fired once.
Here's the altered JS code. Note: I only added the scrollInitialized variable and a check for it in the if statement.
Edit: I also removed the inner if-else case since it was not necessary using this design.
EDIT 2: I originally misunderstood what you wanted to do. What you need to do was add a scrollLock variable that would only be set to true for the duration of your animation. After thinking about this, I implemented it for you. Here is the Jsfiddle:
https://jsfiddle.net/04gaaapo/1/
Here is the new JS code:
$(document).ready(function () {
var scrollLock = false;
var offset;
var anchor = $("#navigation").offset().top;
$(window).bind('mousewheel', function (e) {
offset = $(window).scrollTop();
// if scroll is NOT locked and we are above the anchor
if (scrollLock === false && offset < anchor) {
if (e.originalEvent.wheelDelta < 0) {
// scrolling down
scrollLock = true;
// animate to anchor( nav menu)
$("body, html").animate({
scrollTop: anchor + 1
}, 200);
// unlock in 250ms
setTimeout(toggleLock, 250);
// add nav class
$("#navigation").addClass("nav-fixed");
} else if (e.originalEvent.wheelDelta > 0) {
// scrolling up
scrollLock = true;
// animate to top of page
$("body, html").animate({
scrollTop: 0
}, 200);
// unlock in 250ms
setTimeout(toggleLock, 250);
// remove nav class
$("#navigation").removeClass("nav-fixed");
}
}
});
function toggleLock() {
scrollLock = !scrollLock;
};
});
I'm using this bit of code to hide a menu bar when users scroll on a page. It works fine on Chrome 17.0.963.78 but keeps on flickering in and out on other browsers, namely I.E. firefox and safari ..
$(window).load(function(){
$(document).scroll(function(){
$('#inner_floating').fadeOut();
var scrollA = $('body').scrollTop();
setTimeout(function(){
if(scrollA == $('body').scrollTop()){
$('#inner_floating').fadeIn();
}
}, 100);
})
});
The problem is that your .scroll function is being called for every pixel (or mousewheel tick) scrolled, so the animations are being run many times consecutively.
Try something like this:
$(window).load(function(){
$(document).scroll(function(){
if($("#inner_floating:hidden").length == 0) {
$('#inner_floating').fadeOut();
}
var scrollA = $('body').scrollTop();
setTimeout(function(){
if(scrollA == $('body').scrollTop() && $("#inner_floating:hidden").length > 0){
$('#inner_floating').fadeIn();
}
}, 100);
})
});
This way the animation is only happening if necessary.
I'm creating a scrolling effect using JQuery and I'm wondering if it's possible to distinguish between the user scrolling vs. programmatically scrolling.
I have something like this:
$('#element').on('scroll',function(e){
$('#element').stop(true); // stop previous scrolling animation
$('#element').animate({ // start new scrolling animation (maybe different speed, different direction, etc)
scrollTop:...
});
});
However, this event is triggered during every step of the animation. How can I tell if this event was triggered by the user or by the animation?
Use a variable to determine when you are scrolling programmatically
Example:
var programScrolling = false;
$('#element').on('scroll',function(e){
if (programScrolling) {
return;
}
$('#element').stop(true); // stop scrolling animation
programScrolling = true;
$('#element').animate({
scrollTop:...
});
programScrolling = false;
});
Not sure if that is exactly what you want, but the concept should work.
I would make functions for different kinds of scrollings to detect them and call a scroll handler for all of them, like so:
JS Fiddle
$(window).bind('mousewheel DOMMouseScroll', function(event){
var direction;
if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
direction = 'up';
}
else {
direction = 'down';
}
scrollHandler(direction, 'mouseWheel');
event.preventDefault();
});
var scrollHandler = function(direction, origin) {
var height = $(document).scrollTop();
var movement = (direction == 'up') ? -100 : 100;
console.log(origin);
$('body').stop(true);
$('body').animate({
scrollTop: height + movement
}, 250);
};
Then you can do different stuff according to the origin of the event!
You could also check if the user scrolls to the same direction that the screen is scrolling and do something different, or whatever you want with the info passed by the mousewheel event.
Original mousewheel event function copied from THIS answer
I would suggest possibly using the .originalEvent method. The downside is, this is very browser dependent. See here. Hopefully the following helps:
$('#element').scroll(function(e){
var humanScroll = e.originalEvent === undefined;
if(humanScroll) {
$(this).stop(true);
}
})