I'm working on revamping my website, and the new one can be found on http://beta.namanyayg.com/
There are mainly two things related to scroll on the site:
To check on which 'page' the user is on, by calculating the top offset and scroll position, then adding a class to the page.
To smooth scroll on menu click.
I've written code for both, but there is a lot of lag.
The first one almost always results in lagging. The second one, as a result, lags too. I have included a boolean to check if it's smooth scrolling and disabled the normal scroll events then, but there's not much change.
Do you have any advice on how to improve performance so there is no (or at least, less) lag? Thank you in advance! :)
...Or is it not related to JS at all? I've optimized everything else...
EDIT: Unminified JS at http://beta.namanyayg.com/js/main.js
If you are using underscore, it has an awesome _.debounce function that is excellent for this sort of thing.
To check how much the user has scrolled from the top of the page (i.e. on which 'page' he is at the moment) can be achieved with:
$(window).scroll(function () {
var scrollAmount = $(window).scrollTop(); // in pixels
if(scrollAmount > SOME_AMOUNT)
{
// add required css class
}
});
To scroll smoothly, to some id for example, you could use:
$("html, body").animate({ scrollTop: $("#someID").scrollTop() }, 1000);
These are both jQuery solutions, so you should have jquery library included. There is also a nice jQuery plugin called waypoints that performs these calculations. It might prove useful to you and it has some other nice features and examples.
I have the same problem. I have a scrollable div with thousands of smaller divs. Every time I call scrollTop to get the scroll-position or set it, it sometimes waits at least 1 second.
I read these slides: http://www.slideshare.net/nzakas/high-performance-javascript-2011 (especially slides 138-139) and now I realize that every call to scrollTop, even as a getter, makes javascript relayout the page. This is most likely the cause of delay, but unfortunately I have not found a solution yet, as in a way to call scrollTop without causing relayouts.
Note: I've only been testing on Chrome.
Also read 'Browsers are smart' section of this article: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
I've found an easy solution to the lag with getting scrollTop, just call it inside a scroll-handler and save the result in a variable.
for example in jQuery:
var scrollPos = 0,
element = $('.class');
element.scroll(function(){
scrollPos = element.scrollTop();
});
For the second problem, setting the scrollTop, I reduced the amount of DOM elements by only showing the visible elements. In your case make sure only the visible page(s) are added to the DOM. when scrolling to the next page, in the scroll handler remove the top one (use jQuery .detach) and append the next one to the DOM.
Related
I am trying to add a class to my sticky container once the user scrolls the page past 100px, but it is lagging, and toggling the class uncontrollable.
$(function () {
$nav = $(".topmenu-container");
$(document).scroll(function () {
if ($(this).scrollTop() >= 100) {
$nav.addClass('scrolled');
} else {
$nav.removeClass('scrolled');
}
});
});
This is what I have so far.. I had the same function without an if clause and the toggleClass function instead, but same effect there.
Here you see the container that sticks to the top on scroll, and that I want to add the class to once the user scrolls past 100px from top for example
Edit: I now output the scrollTop value and saw, that it seems to get stuck at the point where the toggle should happen. It keeps jumping between 156px and 87px which makes the toggle happen multiple times a second. Does anyone have an idea?
What you need is rate limiting for your scroll events. In your case, I would suggest throttling, which means that your scroll events are limited to a certain number per second or time unit.
Another option is to use debouncing, but this would cause the event to be triggered only once at the end of the scrolling, which might not be the best solution for your case.
Read more here: Difference Between throttling and debouncing a function
Nice visualization: http://demo.nimius.net/debounce_throttle/
Depending on your use case you may actually get away with the new sticky value for the position property in CSS:
https://developer.mozilla.org/en-US/docs/Web/CSS/position
Additionally, instead of using debouncing and throttling, you could consider using the IntersectionObserver API. The events for InteresectionObserver fire only once (depending on settings) and surely less than scroll which is a hard to optimize event since it fires all of the time. See here:
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
Now, if you have some elements inside the element that depend on the class, such as... the logo having a scaling animation or such, you will definitely have to use IntersectionObserver. It looks like your threshold is 100 pixels, you can definitely configure Interesction Observer to do that.
You can also take a look at this example from Wes Bos which seems to be in one of his free classes:
https://wesbos.com/javascript/06-serious-practice-exercises/scroll-events-and-intersection-observer
I'm hoping you can try these solutions instead of the antiquated scroll thing.
I have two DIVs next to each other. If I scroll the first, the second should scroll too. This is working with this JS Code:
$('#firstDiv').on('scroll', function () {
$('#secondDiv').scrollTop($(this).scrollTop());
});
If I want to apply this to the second DIV too, so that the first DIV scrolls by scrolling the second, I tried it this way:
$('#firstDiv').on('scroll', function () {
$('#secondDiv').scrollTop($(this).scrollTop());
});
$('#secondDiv').on('scroll', function () {
$('#firstDiv').scrollTop($(this).scrollTop());
});
The problem now is, that both are scrolling super slow. Like so slow, that it nearly is not visible.
I guess they start to interact with each other or block each other.
How to do this properly?
They definitively slow down, particularly while scrolling with mouse wheel.
I think it's either use a timeout variable so there's not so many events fired when you're scrolling, or use some javascript code to keep them sync'd directly, like this small <1kb plugin does:
http://asvd.github.io/syncscroll/
I'm having a problem implementing relatively complicated auto-scroll functionality on my page. This displays the issue in my code...
http://codepen.io/d3wannabe/pen/XXxdQq
I have multiple divs on my page (blue,red,green in my example) that I not only want to be able to scroll to (which the top 3 buttons in my example achieve perfectly), but I want to be able to scroll WITHIN (which the bottom 3 buttons represent my best attempt at).
The thing I can't figure out, is why the scroll within function works well on my first div ("scrollTo3rdBlueItem" button), but then less accurately with the other divs ("scrollTo3rdRedItem" and "scrollTo3rdGreenItem" buttons). In my full web application (which obviously has more data to scroll through), I basically see that the lower down the page the parent div is positioned, the less accurately I'm able to scroll within it.
I'm struggling to identify much of a pattern though so can't simply try tweaking the offset values. Any ideas what I might be doing wrong here would be hugely appreciated!!
...since I wasn't allowed to post this without quoting code - here's the jquery function you can see in my codepen!
function scrollToParent(parentID){
$('html,body').animate({scrollTop: $('#'+parentID).offset().top}, 500);
}
function scrollToChild(parentID, childID){
//first focus on the parent
scrollToParent(parentID);
$('#'+parentID).animate(
{scrollTop: $('#'+ childID).offset().top - 100}
, 500);
}
UPDATE
Answer here was COMPLETETLY wrong. Left here to preserve the comments.
UPDATE 2
Got IT! You need to take in to account the offset of the parent div. Update your scrollToChild function to the below;
$('#'+parentID).animate(
{
scrollTop: $('#'+ childID).offset().top - $('#'+parentID).offset().top
}, 500);
I've set up a scrolling website (essentially a parallax-styled page, without the parallax effects) where each "page" is just a div that takes up 100% of the screen. But I need some sort of mechanism to 'lock' the scroll into the correct position so that the div will align properly with the user's browser.
If you need an example, Flickr's splash page does this perfectly.
Thanks.
EDIT: Here's a link to the site I'm working on. The code's a bit messy, and some images aren't loading (since they're not hosted yet) but it's there to give you a rough idea of how the site functions.
http://fiddle.jshell.net/99QjJ/
I just tried to build a fast solution: Fiddle
It prevents the normal scrolling and scrolls just to the appropriate offset of the divs:
if(!scrolling) {
scrolling = true;
currentDiv = (scrollDirection == "down" ? currentDiv + 1 : currentDiv - 1)
$("html,body").animate({
"scrollTop":offsets[currentDiv]
},{queue:true,duration:1000,complete:function() {
window.setTimeout(function() {
scrolling = false;
},200);
}});
It's no complete solution but I think this would work.
Another idea would be using one of the thousands of jQuery plugins which make the page scrollable via the arrow keys. I think if each of the divs fits the entire screen size there's no actual need for scrolling "in between".
So you're doing a 'one page' site, correct? Can't you use anchor tags on each element you want to jump to?
You can animate it to make it look pretty with this nice jQuery plugin
I have a website that I am developing and I have multiple Divs on the main page. I have a div on the right side of the page labeled right_bar2 and I want it to change every 5-10 seconds. The entire div will just be an image that is a link. Basically I assumed the easiest way to do this would be to have a div with a bunch of hidden div's in it and then maybe some javascript that unhides one div at a time and then hides it again and unhides another. However I am unsure the best way to do it. I have looked at a bunch of example and can't get it to work 100% correctly.
Thanks for any advice ;)
JsFiddle examples would be great!
I tried something like this http://jsfiddle.net/VENLh/4/ but in my rails environment/setup, it breaks multiple things, so I'd like something cleaner and easier.
I cleaned it up a bit in this fiddle, but if you said the original breaks multiple things in your original environment, this might not fix them. What specifically did it break?
What I cleaned up was to avoid the need to keep a manual count of the DIVs for the JS or to worry about their IDs. The code is pretty simple:
$(function() {
var $divs = $('div', '#container'),
total = $divs.length,
counter = 0,
showDiv = function() {
$divs.stop().hide();
$($divs[counter]).show('fast');
counter = (conter + 1) % total;
setTimeout(showDiv, 3000);
};
$divs.hide();
showDiv();
});
I didn't perform one optimization that should probably be done. You probably should cache the results of the jQuery selectors on each DIV. It would be easy to do with a jQuery map statement, but I didn't want to muddy the waters here.
The only problem I can see in this case is if you are going to use heavy image, it may take some time to load. As the image will start getting loaded when you show it first time. So for this I would say you should keep the opacity 0 and load the image at the time of pageload.
And also to remove the delay you are having where one div is getting hidden and other is getting visible can be removed by using opacity. reduce opacity of one from 100 to 0% and for other increase from 0 to 100%.