I'm using the plugin Smooth Scrollbar (here).
I have an animation on my fixed header (outside the smooth scrollbar container) and triggered when user starts scrolling the smooth scrollbar container. As mentioned in the documentation (here), it's not possible that scrollbars fire scroll events. So we have to use:
scrollbar.addListener((status) => {
...
});
This is the code to animate my fixed header:
$(window).scroll(function() {
if ($(this).scrollTop() > 50){
$('.site_header').removeClass('is--large').addClass('is--small');
}
else{
$('.site_header').removeClass('is--small').addClass('is--large');
}
});
I can't figure it out how to integrate it with Smooth Scrollbar plugin. I tried various solutions to use addListener but I can't make it work.
Any help would be much appreciated!
I know it's been a while but:
const scroller = document.querySelector('.scrollable');
const bodyScrollBar = Scrollbar.init(scroller, { damping: 0.1, delegateTo: window, alwaysShowTracks: false });
bodyScrollBar.addListener( () => {
if (bodyScrollBar.scrollTop > 50){
$('.site_header').removeClass('is--large').addClass('is--small');
}
else{
$('.site_header').removeClass('is--small').addClass('is--large');
}
}
)
where .scroller is my scrolling container. Whenever you call the variable bodyScroller in the console you can see all options set and what value you can retrieve at any time. In this instance, by calling .scrollTop (NOT a function) you can retrieve its offset top value at any time.
Related
I have a navigation menu set to display:none, which appears upon scroll and disappears once back at the top.
Is there a way to disable the scroll function once I reach a certain breakpoint (ex. max-width: 786px) and display the menu?
Javascript
$(window).on("scroll", function() {
if($(window).scrollTop()) {
$('nav').addClass('show');
}
else {
$('nav').removeClass('show');
}
})
CSS
.show {
display: block
}
You can solve this using either javascript or CSS, however I would personally go with the javascript one.
First up, for a javascript solution, the function you need is:
window.innerWidth
It will return the entire window width not including scroll bars. Read more about it here.
So, as Temani Afif suggested, you would write a test inside your scroll function to check for the desired window width like so:
$(window).on("scroll", function() {
if (window.innerWidth <= 786) return;
// Your other code here
})
For a purely CSS solution, you could override the effect of the 'show' class with a media query:
.show {
display: block
}
#media screen and (max-width: 786px) {
nav {
display: block !important
}
}
More on media queries here
You can activate/deactivate the scroll listener on browser resize. This way your scroll listener wont be called everytime user scrolls when browser width is more than 786px.
var scrollListenerActive = false;
var handleScrollListener = function() {
if( $(window).width() < 786 && !scrollListenerActive ) {
$(window).on("scroll", function() {
if($(window).scrollTop()) {
$('nav').addClass('show');
}
else {
$('nav').removeClass('show');
}
});
scrollListenerActive = true;
} else {
$(window).off("scroll");
scrollListenerActive = false;
}
}
$(document).ready(handleScrollListener); // attach the listener on page load
$(window).resize(handleScrollListener); // attach/remove listener on window resize
That's a good strategy above, however the event you want to listen for is simply 'resize', on the window object (some older browsers can do it on any dom element, but better to be consistent and current with the standard).
So something like:
window.addEventListener('resize',function(){
if(window.innerWidth >= 768){
document.body.style['overflow-x'] = 'hidden';
}
else{
document.body.style['overflow-x'] = 'auto';
}
});
You can trade 'auto' for 'scroll' if you want the scrollbar to always show when less than 768.
Similarly, you can switch out 'overflow' instead of 'overflow-x' if you want to affect both scrollbars.
Keep in mind that the event tends to fire for every width and height change as the window is resized, in case you have other logic that might have an issue with firing many times (thousands or more) as it is resized.
This also works on maximize/restore, as they trigger the resize event as well.
Here's MDN's doc on the resize event if needed:
https://developer.mozilla.org/en-US/docs/Web/Events/resize
This is vanilla javascript, so it should work whether you're using a lib like jquery or not.
I have a fixed sidebar and a fixed header with scrollable content in the main section of the page. The header is to be triggered on the scroll to hide the top portion of itself on scroll down and then show itself on scroll up. The sidebar can be triggered to hide and show itself with a button. When this happens the header gains back the full width of the page until the button is pressed to bring back the sidebar. The page loads with the sidebar opened.
So far I've been able to get the sidebar to transition off and back on the page properly. I also have the header working as intended on page load. However the issue I'm having is with the transition, more so recognizing the changed classes when the sidebar closes. I believe my issue is with the scroll javascript not recognizing the sidebar is closed because when scrolling it applies the classes to the header for when the sidebar is open. To test this I added a class called SEEME123 which never shows.
Below is the javascript for scrolling changes.
var exploreOpen = $('#explore').hasClass('open');
var exploreClosed = $('#explore').hasClass('closed');
$(function () {
var position = $(window).scrollTop();
if (exploreOpen) {
$(window).scroll(function () {
var scroll = $(window).scrollTop();
if (scroll > position) {
$('#wrapper-site-header').removeClass('explore-open--header-full');
$('#wrapper-site-header').addClass('explore-open--header-reduced');
} else {
$('#wrapper-site-header').addClass('explore-open--header-full');
$('#wrapper-site-header').removeClass('explore-open--header-reduced');
}
position = scroll;
});
} if (exploreClosed) {
$(window).scroll(function () {
var scroll = $(window).scrollTop();
if (scroll > position) {
$('#wrapper-site-header').removeClass('explore-closed--header-full');
$('#wrapper-site-header').addClass('explore-closed--header-reduced');
$('#wrapper-site-header').addClass('SEEME123');
} else {
$('#wrapper-site-header').addClass('explore-closed--header-full');
$('#wrapper-site-header').removeClass('explore-closed--header-reduced');
}
position = scroll;
});
} else {}
});
The javascript for the sidebar function toggles the open and closed classes on the sidebar, along with removing or adding the appropriate header class.
I don't understand why this isn't working as intended and would like to know how to resolve the issue. I've searched around attempting to understand where I screwed up, or to find an example where the scroll function does X because of Y. I've also attempted the above without variables (ie..
$(function () {
var position = $(window).scrollTop();
if (('#explore').hasClass('open')) {
), and as separate functions.
Anyway, here is a jsfiddle in case I missed something. https://jsfiddle.net/at0yxo0m/
Thank you all for your help and advice.
EDIT: Additional information.
I do have an earlier version of this layout where the scroll function only changes the header area that works with closing the sidebar. However the animations were clunky in general, and worse on mobile. Also to get everything to work right I had to wrap elements more than I thought was needed. So it was my goal to streamline as much as I could while getting the desired result.
I'm working on a slideshow area. I want to make it so scrolling horizontally will trigger an animation which moves the scrollable area to the next "slide."
Everything is working, but only if I scroll just a tiny bit. If I scroll more, the GSAP scrolling animation fails silently.
There are two ways that would make sense for this to be solved which I can think of:
1 > The first would be cancelling the scroll behavior, something like this:
$viewing_area.scroll( function(event) {
if(animationIsInProgress) {
event.preventDefault();
}
}
But this way is likely to stop GSAP scrolling as well. There is no way to distinguish if the scrolling is due to GSAP or the user that I know of.
2 > The second way would be to have GSAP force it's scrolling over anything the user is doing:
TweenLite.to($viewing_area, time, {
scrollTo: { x: slide_stops[nextTarget] },
ease: Power4.easeInOut,
onComplete: function() {
console.log('scrolling completed');
animationIsInProgress = false;
}
//Some option for forcing the behavior over user scrolling
});
Are either of these things achievable, or is scrolling by it's nature, unstoppable?
It ends up, GSAP scroll to plugin has a setting for this:
http://greensock.com/docs/#/HTML5/GSAP/Plugins/ScrollToPlugin/
It is called autokill, and if it is set to false, user scrolling will not interrupt the tween.
TweenLite.to(myDiv, 2, {scrollTo:{y:400, autoKill:false}, ease:Power2.easeOut});
I am using bootstrap 3 and have a fullscreen hero unit at the top of my page, below that is my navigation. I have some js which allows my navbar to stick to be fixed at the top after you scroll past the full screen hero. Also some js for my smooth scrolling links.
The problem is the offset is different before you scroll past the full screen hero and after. But it works fine when you are past the jumbotron. I have tried a bunch of different things but I can seem to get this to work exactly.
Check out the fiddle here.
Here is my js for the smooth scrolling links:
$(document).ready(function() {
// navigation click actions
$('.scroll-link').on('click', function(event){
event.preventDefault();
var sectionID = $(this).attr("data-id");
scrollToID('#' + sectionID, 750);
});
// scroll to top action
$('.scroll-top').on('click', function(event) {
event.preventDefault();
$('html, body').animate({scrollTop:0}, 1200);
});
// mobile nav toggle
$('#nav-toggle').on('click', function (event) {
event.preventDefault();
$('#main-nav').toggleClass("open");
});
});
// scroll function
function scrollToID(id, speed){
var offSet = 95;
var targetOffset = $(id).offset().top - offSet;
var mainNav = $('#main-nav');
$('html,body').animate({scrollTop:targetOffset}, speed);
if (mainNav.hasClass("open")) {
mainNav.css("height", "1px").removeClass("in").addClass("collapse");
mainNav.removeClass("open");
}
}
if (typeof console === "undefined") {
console = {
log: function() { }
};
}
By changing var offSet = 95; I am able to adjust the offset but what would be the best way to use 180 before the navbar sticks to the top but 95 when it does?
Also here is the js I am using for my navbar:
$(function () {
/* $(".navbar-fixed-top").css({"top":$(".jumbotron").height()});
$(window).resize(function (e) {
$(".navbar-fixed-top").css({"top":$(".jumbotron").height()});
});*/
$(document).on( 'scroll', function(){
console.log('scroll top : ' + $(window).scrollTop());
if($(window).scrollTop()>=$(".jumbotron").height())
{
$(".navbar").addClass("navbar-fixed-top");
}
if($(window).scrollTop()<$(".jumbotron").height())
{
$(".navbar").removeClass("navbar-fixed-top");
}
});
});
Are you open to angular.js? I have a directive i use for this. As seen here.
I'll grab the plunker link for you. you might find the code helpful.
Essentially you need to create a ghost dom element to take the place of the menu when you pull it to an new layout position.
EDIT: Here it is
I won't suggest grabbing angular just for this. But you can use the basis of the events and logic to build your own solution.
This here is creating an element and placing in its place
$scope.spacer = $element.after(
'<div class="spacer" style="height:' + $element[0].clientHeight + 'px"> </div>').next();
then this element is removed when the menu is back to its static position.
Inspect the dom and watch how it changes, this will probably help you see the events and changes that need to take place.
EDIT 2 SOLUTION:
HERE is the concepts applied to your JSFiddle
It's not the best solution but by adding margin: 0 0 -100px 0; to your .navbaryou lose the spacing issue.
Also you're getting 22 console errors because of missing images. I'm not saying that this is causing any major problems but you would be better off losing them.
The problem is that when you have not scrolled past the hero, navigation is still part of the layout and pushes content bellow it a little lower. When you scroll past (either manually or via a script) the hero, navigation is removed and fix positioned. That makes everything which was bellow to "jump up" exactly of the navigation height.
That means if portfolio was 1000px from the top, on click you say: go 1000px from top; but then porfolio moves 100px up (as explained above) meaning it is now 900px from the top while the window scrolled 1000px as you asked.
When you have scrolled past the hero, nothing changes its position.
I'm using a nicescroll a plugin that I use to create scrollbars on divs.
$('#postscroller').niceScroll();
var nice = $("#postscroller").getNiceScroll()[0];
$('#postscroller').bind("scroll",function()
{
if(nice.scrollvaluemax==nice.scroll.y)
{
alert('bottom');
}
alert(nice.scroll.y);
});
First I activate the div to be scrolled.
Then I save the nicescroll instance to the nice variable.
When I test the scroll event to see wether the scroll.y is being fired when I scroll to the bottom I get some numbers but not 134 which is nice.scrollvaluemax in the div I'm testing.
I do get however 134 when I'm at the bottom and I scroll upwards.
Any idea on how can I get 134 when scrolling to the bottom?
Thanks
you get other numbers because you are not at the bottom when you scroll down...
probably related to your current position when the scroll is fired.
post more code.
I fixed it by calling this at the scroll event
var postscrollertimer = (function() {
var timer;
return function() {
clearTimeout(timer);
timer = setTimeout(function()
{
if(postscroller.scrollvaluemax==postscroller.scroll.y)
{
//do stuff
}
}, 1000);
};
})();