jQuery Scroll Function Does Not Fire (Scroll Too Fast) - javascript

I am seeing that if a user scrolls too fast, the below jQuery function does not fire. Is this a performance issue/bug within jQuery detection of the event or do I need to do something with my code?
...Or, is there a better way [at least performance reliability wise] to call it with pure JavaScript? If so, how do I code it?
$(window).scroll(function() {
var st = $(this).scrollTop();
if(st < 50){
$('.header_wrapper').css({'marginTop':-50});
} if(st < 40){
$('.header_wrapper').css({'marginTop':0});
}
});
You can see it in action here: http://www.walkingfish-grainboards.com/privacy-policy/
Thnx for your help - it would be greatly appreciated.

Since you are considering performance:
$(window).on('scroll',function(){
var st = $(this).scrollTop(),
mTop = ((st < 40) ? 0 : -50);
$('.header-wrapper').css({marginTop:mTop});
});
Rather than put the assignment in the if you can just put the value, then do the assignment once based on the value. With your current statement, the -50px value you remain no matter how far down you go (as you never clear this value), and would only return to 0 when you scrolled back to the top. Hence, you do not need to have the nested if statement.
If you really wanna kick it up a notch, include caching:
var scrollStuff = {
headerWrapper:$('.header-wrapper'),
onScroll:function(){
var self = this,
st = $(self).scrollTop(),
mTop = ((st < 40) ? 0 : -50);
self.headerWrapper.css({marginTop:mTop});
}
};
$(window).on('scroll',function(){
scrollStuff.onScroll();
});
By caching everything including the function, you won't need to requery the DOM every time for the element you are applying the marginTop to.

Well, I over thought it originally. This works great:
$(window).scroll(function(){
yos = (window.pageYOffset > 48);
$('.headerwrap').toggleClass('stick', yos);
$('.pagetitlewrap').toggleClass('headerwrap_stuck', yos);
});

Related

can't change z index with javascript

I'm trying to change the Z index of an image according to the scroll position,currently in chrome (but it should be working on all broswers).
anyway, it's not working on chrome, unless I get into inspection mode and I don't understand why it's only working in inspection mode?
this is the script:
$( window ).scroll(function() {
var scrollTop = $(window).scrollTop();
if ($(this).scrollTop()>700) {
document.getElementById("back-ground-image").style.zIndex = "-9";
console.log("-9");
} else {
document.getElementById("back-ground-image").style.zIndex = "-19";
console.log("-19");
}
});
Problem
What you need is $(document) not $(window).
By default, you scroll the $(document), not the $(window).
However, when you open your Chrome DevTools, the $(window) is not being scrolled which is why your code works.
To fix the issue, change $(window).scroll() to $(document).scroll() and $(window).scrollTop() to $(document).scrollTop()
Improvements
1. Use jQuery functions
Also, if you're already using jQuery, why not use jQuery selectors and .css():
$("#back-ground-image").css('zIndex', '-9')
instead of
document.getElementById("back-ground-image").style.zIndex = "-9";
2. Use DRY code
(Don't Repeat Yourself)
If you follow recommendation #1, why not set $("#back-ground-image") to a variable instead of repeating it twice.
$(document).scroll(function() {
var scrollTop = $(document).scrollTop(),
$bkImg = $("#back-ground-image");
if ($(this).scrollTop() > 700) {
$bkImg.css('zIndex', '-9');
console.log("-9");
} else {
$bkImg.css('zIndex', '-19');
console.log("-19");
}
});
Otherwise, you could use:
$(document).scroll(function() {
var scrollTop = $(document).scrollTop(),
background = document.getElementById("back-ground-image");
if ($(this).scrollTop()>700) {
background.style.zIndex = "-9";
console.log("-9");
} else {
background.style.zIndex = "-19";
console.log("-19");
}
});

How to know what part of HTML is the user on

so I want to know how I can get what section or part of my html I’m currently on. An example
So how do I know if a user has already scrolled down over part 2 using JavaScript
Or if they’re currently at part 1
<html>
<head>
</head>
<body>
<section class=“part 1”>
</section>
<section class= “part2>
</section>
</body>
</html>
The following codes will give you a little idea about how to handle this situation. Essentially you are going to want to get the scrollbar position which you can do using:
document.documentElement.scrollTop
You also want to get a range where the element you are looking for resides, in our case, it is .part1 and .part2. We can get that range by using offsetTop as the beginning of the limit and offsetTop + clientHeight to determine the end.
You are going to have to keep track of the window scroll event.
The following example is generic:
$(window).scroll(function(e) {
if (document.documentElement.scrollTop > 0
&& document.documentElement.scrollTop < $('.part2').offset().top ) {
$('div').html("At part1")
} else {
$('div').html("At part2")
}
});
JSFiddle
Likewise, if you want a little bit of modularity:
$(window).scroll(function(e) {
let watchList = ['part1', 'part2', 'part3'];
let scrollTop = document.documentElement.scrollTop;
for (var classname of watchList) {
let el = document.getElementsByClassName(classname)[0];
if (scrollTop > el.offsetTop &&
scrollTop < el.offsetTop + el.clientHeight) {
$('div').html("At <strong>"+classname+"</strong>");
}
}
});
JSFiddle
The possibilities are limitless to continue and make this more useful, but I'll leave that up to you.
you can use is[":focus"] function to find which div has focus currently.
if($(".part1").is(":focus"))
{
//you code
}
else if($(".part2").is(":focus"))
{
//you code
}
you can use mouseenter function it fires when the mouse goes into that div for the first time.
$(".part1").on('mouseenter', function(){
//your command
});
you can use mouseover function to find where is mouse right now. it fires when mouse moves inside that div.
$(".part1").on('mouseover', function(){
//your command
});
You can use javascripts offsetTop functionality. This is a parameter that returns how far down from the top a div is in the number of pixels.
It can also return how far down the user has scrolled when called on the window object itself. Then it's just a matter of math. See if the user has scolled down far enough to be past the div in reference.
For example:
var part1DivOffset = document.getElementsByClassName("part 1")[0].offsetTop;
var part2DivOffset = document.getElementsByClassName("part2")[0].offsetTop;
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
This code will get you 3 variables. The first 2 lines save the offsetTop of the div's. While the third line detects how far down the user has scrolled. Then you can do math with the variables:
if(scrollTop >= part1DivOffset){
//we are past part1
}
if(scrollTop >= part2DivOffset){
//We are past part 2
}
if(scrollTop >= part1DivOffset && scrollTop < part2DivOffset){
//We are past part 1 but not past part 2
}

Toggle class when object visible in the viewport

I need a script which toggle a class when another class or section is visible in the viewport (during scrolling).
Here I have an script which works for precised distance from top, but can somebody help me to modify it for my needs?
$(window).scroll(function(){
if ($(this).scrollTop() > 50) {
$('#viewport').addClass('turn_on');
} else {
$('#viewport').removeClass('turn_on');
}
});
A couple of things. First the scroll event (as well as the resize event) fire multiple times. Traditionally, developers have used something called debouncing to limit the number of times a function fires. I've never got it to work correctly, so instead I check if a condition is met before continuing. You are basically doing this already.
var bool = false
$(window).on('scroll', function(){
if(!bool){
bool = true;
//fire the function and then turn bool back to false.
};
});
The next thing you need is to identify the element to add the class to. Let's say it has an id of foo.
var yOffset = $('#foo').offset().top;
From here, you'll need to compare the current vertical scroll position with that of the yOffset. You may also need to add the height of the element for when it scrolls out of frame.
var elHeight = $('#foo').height();
The element should be completely in frame with the $(window).scrollTop() equals the yOffset and out of frame when the $(window).scrollTop() is greater than yOffset + elHeight.
This is all assuming the element isn't in the frame to begin with. If it is, it will be trickier but it's a start.
Working fiddle
Try to add function that detect if element passed in argument is visible :
function isVisisble(elem){
return $(elem).offset().top - $(window).scrollTop() < $(elem).height() ;
}
$(window).scroll(function(){
if (isVisisble( $('your_element') ))
$('#viewport').addClass('turn_on');
} else {
$('#viewport').removeClass('turn_on');
}
});
Hope this helps.
Thx everyone for help.
Here I found the solution: LINK
And here is the modified script:
$(document).ready(function () {
var windowHeight = $(window).height(),
gridTop = windowHeight * 0.1,
gridBottom = windowHeight * 1;
$(window).on('scroll', function () {
$('.inner').each(function () {
var thisTop = $(this).offset().top - $(window).scrollTop();
if (thisTop > gridTop && (thisTop + $(this).height()) < gridBottom) {
$(this).addClass('on');
}
});
});
});

Javascript doesn't work in firefox and IE/edge

I have a piece of code, that's changing my div background on mousescroll and it's working fine in Chrome and Opera, but it doesn't in Firefox and IE/Edge.
I have two divs, the inner one has a background image that is changing on scroll down, the outer one is simply bigger so there is space to scroll.
In Firefox and IE/Edge, the scroll or doesn't work either skips an image, sometimes even doesn't purceed to scrolling the rest of the content on the website.
http://jsfiddle.net/s6qrfo9n/1/
Any ideas why?
Here it is (and I know it's poorly written, but I'm new to javascript and it does the job):
$(document).ready(function(){
var numberofscroll = 0;
var lastScrollTop = 0;
$("#home").scroll(function(){
var st = $(this).scrollTop();
(st > lastScrollTop) ? numberofscroll++ : numberofscroll--;
console.log(numberofscroll);
console.log(lastScrollTop);
console.log(st);
if (numberofscroll<2){
change_background2(numberofscroll);
}
else if (numberofscroll<3){
change_background3(numberofscroll);
}
else if (numberofscroll<4){
change_background4(numberofscroll);
}
lastScrollTop = st;
});
function change_background2(numberofscroll){
var i;
for (i = 2; i <= 2; i++) {
$("#home").css("background-image","url('images/movie_" + i + ".jpg')");
}
}
function change_background3(numberofscroll){
var i;
for (i = 3; i <= 3; i++) {
$("#home").css("background-image","url('images/movie_" + i + ".jpg')");
}
}
function change_background4(numberofscroll){
var i;
for (i = 4; i <= 4; i++) {
$("#home").css("background-image","url('images/movie_" + i + ".jpg')");
}
}
});
The problem lies in the smooth scrolling feature of firefox and ie (see this question). This causes the jQuery scroll event to fire multiple times every time you scroll, thus the 'missing' images--they are being put in, but then they're replaced so fast you can't see them.
Unfortunately, since you can't disable the smooth scrolling feature on people's browsers, there isn't really a perfect solution to this. The best solution is to debounce your scroll event handler. There are many ways to implement a debounce (google it for some ideas). A simple one would be just toggling a boolean after a timeout and checking it every time you run the function:
var dontHandle = false;
$("#home").scroll(function () {
if (dontHandle) return; // Debounce this function.
dontHandle = true;
window.setTimeout(function() {
dontHandle = false;
}, 400); // Debounce!--don't let this function run again for 400 milliseconds.
});
Here's your updated JSFiddle. You may need to play with the debounce time. Best of luck.
I'd say your code is working as intended but I have a couple thoughts about the scroll event.
The scroll event will only be fired if scrolling actually takes place. Nothing will happen if your div doesn't scroll. You could get around that by using another library, check out this stackoverflow answer for some suggested libraries. Also, keep in mind that the scroll event is extremely sensitive, so the "skipping" of images may simply be a result of scrolling too fast.
I cleaned up your code to make better use of the change_background function.
var numberofscroll = 0;
var lastScrollTop = 0;
$(document).ready(function(){
$("#home").scroll(function(e) {
var st = $(this).scrollTop();
console.log(numberofscroll, lastScrollTop, st);
(st > lastScrollTop) ? numberofscroll++ : numberofscroll--;
//make sure numberofscroll stays in range
if(numberofscroll <= 0) {
numberofscroll = 1;
} else if(numberofscroll > 4) {
numberofscroll = 4;
}
change_background(numberofscroll);
lastScrollTop = st;
});
function change_background(numberofscroll) {
$("#home").css("background-image","url('http://coverjunction.s3.amazonaws.com/manual/low/colorful" + numberofscroll + ".jpg')");
}
});
Your change_background functions have been rolled into one function and numberofscroll will stay within a certain range to ensure the image you want actually exists.
Hope that helps!

Variable two options

Had a look around and couldn't find anything that solved this very simple problem.
I'm still learning jQuery so prior apologies for my stupidity on this one, I know it's a very simple fix but things like using || and trying to using if and else inside a var don't see to work for me.
Essentially this is what I have currently. All I want is to add/remove the class "whitebg" depending on the scroll position and height of the element, which works well.
The problem is trying to query two different elements that each need a different height buffer as you can see (-167 and -90) so cannot be grouped, but need to be 'either / or' so both are accounted for.
Many thanks
Rb
jQuery(window).scroll(function() {
Menuresize();
});
function Menuresize() {
var myheight = jQuery(".section-image-slider, .section-video-slider").height() - 90;
var myheightalt = jQuery(".area-tag").height() - 167;
var scroll = jQuery(window).scrollTop();
if (scroll > myheight) {
jQuery(".bt-menu").addClass("whitebg");
}
elseif (scroll > myheightalt){
jQuery(".bt-menu").addClass("whitebg");
}
else {jQuery(".bt-menu").removeClass("whitebg");}
};
jQuery(window).resize(function() {
Menuresize();
});
If I understand your problem correctly, toggleClass can take a boolean parameter to toggle on/off the class specified. You can then work out a compound boolean expression that results in true or false:
e.g.
jQuery(".bt-menu").toggleClass("whitebg", scroll > myheight || scroll > myheightAlt);
I found the question a little hard to follow so, if it is something else you wanted, please clarify :)
Have your Menuresize function take parameters for the selectors and height, and then just call it for each:
function Menuresize(selector, height) {
var myheight = jQuery(selector).height() - height;
var scroll = jQuery(window).scrollTop();
if (scroll > myheight) {
jQuery(".bt-menu").addClass("whitebg");
}
else {
jQuery(".bt-menu").removeClass("whitebg");
}
};
jQuery(window).resize(function() {
Menuresize(".section-image-slider, .section-video-slider", 90);
Menuresize(".area-tag", 167);
});

Categories