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/
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'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 have several divs that I want to have fade in and out depending on a nav panel. I am running into an issue with two of the divs, but the others work fine so I am not sure what is happening.
here is the jQuery code, here the two divs that are wacky have been singled out, the real code generalizes it to work for all divs:
$('#behind_the_lens').click(function() {
$('#gallaries-page').fadeOut(0);
$('#behind_the_lens-page').fadeIn(750);
$('#pricing-page').fadeOut(750);
});
$('#pricing').click(function() {
$('#pricing-page').fadeIn(750);
$('#behind_the_lens-page').fadeOut(750);
});
When the first function runs #pricing-page just hides, no fading and #behind_the_lens-page does fade.
When the second function runs #pricing-page waits for #behind_the_lens-page to fade out, then it instantly shows.
this does not happen for any other combination of divs so it is very strange to me.
as for the contents of these divs, one #pricing-page uses a table and the other uses a floating layout. but there layouts types are not unique from other divs.
In summary, why is it working this way for these divs but not the others? furthermore, why is it doing this at all?
Edit: was able to come up with a fiddle here that shows the problem.
You are fading in and fading out simultaneously. Watch the scrollbar, your "clicked" page is appearing as the currently visible is disappearing, and jumps up into position after the visible completely disappears (display:none).
Use the complete callback on fadeOut so that fading in happens after fading out finishes.
https://jsfiddle.net/u3u8jsqr/2/
JS
if (thisID != visibleID) {
$(visibleID).fadeOut(750, function () {
$(thisID).fadeIn(750);
});
}
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.
I have a div with a horizontal scroll.
Is there any way I can detect the click on the horizontal scrolls
arrow using jQuery ?
Note:
Actually I want the scroll to move a fixed no of pixels to the right when the user clicks the right scroll arrow and vice versa.
The event should not be triggered on scroll. It should be only triggered if user explicitly clicks the scrolls arrow.
There are multiple divs having scrollbars, having same class and no ids.
Would prefer to not use any plugins
Here is a demo for what you want
http://jsbin.com/opufow/4/edit
I hope this will help you?
you can use .scroll function of jquery.
Edit 2: Another suggestion is to do something like this depending on your implementation of scrolling areas (see working jsfiddle):
function CustomScrollArrow(elementToScroll) {
var $el = $(elementToScroll);
return $('<a>Click me to scroll</a>').css(/*...*/).click(function(){
$el.scrollLeft($el.scrollLeft()+10);
});
}
$('.ScrollAreaClass').each(function(){
// You could choose to append to your scrolling
// areas or their wrapper classes or whatever...
$('body').append(new CustomScrollArrow(this));
});
Afterwards it's just a matter of styling your handmade arrows.
Edit 1: I've seen you updated your question, so here's an updated answer with an alternative solution.
You can try to circumvent the problem by using a customized scrollbars implementation, for example jScrollPane by Kelvin Luck or any other, whatever. If the solution offers click events on arrows - then you're set. Otherwise just do a bit of tinkering...
I maintain, however, my point of view that unless you are looking to perform an action before the browser executes the arrow click, I would recommend adding an event handler to the actual result of that click, i.e. the scroll.
Doing this will help to avoid inconsistencies across various implementations of scrolling in browsers; will keep working if scrolling is performed in another manner (i.e. swipe gesture); will still work if there's some javascript code that replaces the default browser implementation of scrollbars.
jQuery offers the .scroll handler to capture scrolling and .scrollLeft to determine the resulting position of the horizontally scrolled content.
Try a working jsfiddle or see the code below:
// Cache the initial scroll position:
var initialLeftScroll = $('#wrapper').scrollLeft();
// Bind event:
$('#wrapper').scroll(function (ev) {
// Get new horizontal scroll offset:
var currentLeftScroll = $('#wrapper').scrollLeft();
// Determine the difference
// (did the user scroll horizontally or just vertically?):
var leftScrollDifference = currentLeftScroll - initialLeftScroll;
// Now we can check
if (leftScrollDifference) {
/* Do something here */
}
// Reset the cache:
initialLeftScroll = currentLeftScroll;
});