I have a site where I am trying to use a scroll event to
1) fade out a textual version of the company name,
2) replace the content of that element with an image file of the company logo and
3) fade the logo back in. Issues I'm facing:
I'm able to get the fade out to work, but cannot get the replace (.html) function and fadeIn method to work at all
I notice that the fade out does not take place immediately upon the user scrolling beyond 250px from the top; it lags quite a bit, especially with faster page scrolling.
I've tried both the .animate and .fadeIn/.fadeOut versions for the fading, but still had no luck with the callback function properly replacing the element contents and fading it back into view.
My code is below:
jQuery(window).scroll(function() {
var scrollTop = $(this).scrollTop();
var data = '<img src="assets/template/images/afl_logo_sm.png" width="135" height="55" alt="AFL">'
console.log('Scroll ', scrollTop);
if (scrollTop >= 250) {
jQuery('a.navbar-brand').stop().animate({
opacity: 0.0
}, 500, function() {
jQuery('a navbar-brand').html(data).fadeIn('fast');
});
}
});
Thanks for any help you can provide,
Sandman
You are missing the class selector in the fadein/html code, you are using the class like a descendant selector
jQuery(window).scroll(function () {
var scrollTop = $(this).scrollTop();
var data = '<img src="//placehold.it/135X55" width="135" height="55" alt="AFL">'
if (scrollTop >= 250) {
jQuery('a.navbar-brand').stop().animate({
opacity: 0.0
}, 500, function () {
jQuery(this).html(data).animate({
opacity: 1
});
});
}
});
Demo: Fiddle
Also, once the animation is done, I think the further scrolling should not repeat it so
var flag = false;
jQuery(window).scroll(function () {
var scrollTop = $(this).scrollTop();
var data = '<img src="//placehold.it/135X55" width="135" height="55" alt="AFL">'
if (scrollTop >= 250) {
if (!flag) {
flag = true;
jQuery('a.navbar-brand').stop().animate({
opacity: 0.0
}, 500, function () {
jQuery(this).html(data).animate({
opacity: 1
});
});
}
}
});
Demo: Fiddle
As for the lagging, the browser is a single threaded application so when there is a faster scrolling the browser may spend more time on updating the view as per the scroll than in the script executing which handles the fadeIn
Related
Scroll Setup
I'm using the popular scroll detection method to hide a nav element on scroll down and show it on scroll up.
$(window).scroll(function(){
currentScrollTop = $(window).scrollTop();
if (currentScrollTop > lastScrollTop) {
// On scroll down
$('nav').removeClass('active');
console.log('Down');
} else {
// On scroll up
$('nav').addClass('active');
console.log('Up');
}
lastScrollTop = currentScrollTop;
logScroll();
});
Barba.js Transitions
I'm also using barba.js with page transitions that all work fine. Every time I load a new page I run a transition and I also run a few of my own custom functions, which have no effect on the scrolling apart from:
$(window).scrollTop(0)
I use to scroll back up to the top of the document. It works cross browser.
var FadeTransition = Barba.BaseTransition.extend({
start: function() {
// This function is automatically called as soon the Transition starts
// this.newContainerLoading is a Promise for the loading of the new container
// (Barba.js also comes with an handy Promise polyfill!)
// As soon the loading is finished and the old page is faded out, let's fade the new page
Promise
.all([this.newContainerLoading, this.fadeOut()])
.then(this.fadeIn.bind(this));
},
fadeOut: function() {
// this.oldContainer is the HTMLElement of the old Container
return $(this.oldContainer).animate({ opacity: 0 }).promise();
},
fadeIn: function() {
// this.newContainer is the HTMLElement of the new Container
// At this stage newContainer is on the DOM (inside our #barba-container and with visibility: hidden)
// Please note, newContainer is available just after newContainerLoading is resolved!
// Custom — Add scrollTop
$(window).scrollTop(0);
resetScrollTop();
// Custom - History ScrollTop
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
var _this = this;
var $el = $(this.newContainer);
$(this.oldContainer).hide();
$el.css({
visibility : 'visible',
opacity : 0
});
$el.animate({ opacity: 1 }, 400, function() {
// Do not forget to call .done() as soon your transition is finished!
// .done() will automatically remove from the DOM the old Container
_this.done();
});
}
});
Reset Scroll
I've also added a custom function that I'm running at the same time to try and reset all of the scrolling.
function resetScrollTop() {
currentScrollTop = $(this).scrollTop();
lastScrollTop = 0;
$('nav').removeClass('active');
}
I've even experimented by setting currentScrollTop to zero, which is obviously overwritten on the first scroll, but that doesn't seem to have any effect (and neither does removing the reset function entirely):
currentScrollTop = 0
Console Logs
I've been logging the two values next to each other to try and establish what's going on:
function logScroll() {
console.log(currentScrollTop + ' ' + lastScrollTop);
}
When I load the first page and scroll down normally currentScrollTop is always at least lastScrollTop + 1:
But after each barba transition, when I scroll down I find that currentScrollTop and lastScrollTop are equal some of the time, which I think is what is causing the problem. I just have no idea what would cause them to increase in sync:
Any help / ideas would be massively appreciated.
I fixed this in the end by running resetScrollTop() both when the transitions were at onEnter and onCompleted.
I also added $('.js-nav').addClass('hide') to the onLeave function which added visibility: hidden; to the .nav element.
I then added $('.js-nav').removeClass('hide'); to the scroll down condition in the function.
Feels messy, but seemed to do the trick, is performant and works across latest Chrome, Firefox and Safari.
I'm looking to use javascript to animate the content of a nested DIV within an parent slide when the parent slide moves into the viewport.
At the moment, the content in the nested DIV only animates once a scroll command is also triggered after the parent slide moves onto the screen. I believe this is because the slide motion is animated and not scroll controlled.
The same issue is at play in this JSFiddle demo I created to explore the issue:
http://jsfiddle.net/9dz3ubL1/
(The animated movement of the slide from right to left in this demo has been created to test for this problem, to replicate the motion of the slide without scrolling; it is not actually a feature of the development proper).
My question is, how can I script for the animations to be triggered for each nested DIV, when each slide element moves into the viewport, without requiring a scroll function?
Thanks for any help. Here's the script I'm using to control opacity and other CSS stylings.
$(document).ready(function() {
/* Every time the window is scrolled ... */
$(window).scroll(function() {
/* Reveal hidden_header delayed */
$('.hidden_header').each(function(i) {
var center_of_object = $(this).offset().left + $(this).outerWidth();
var center_of_window = $(window).scrollLeft() + $(window).width();
/* If the object is completely visible in the window, fade it it */
if (center_of_window > center_of_object) {
$(this).animate({
'opacity': '1'
}, 500);
$(this).animate({
'right': '0'
}, 1500);
}
});
/* Reveal hidden_content delayed */
$('.hidden_content').each(function(i) {
var center_of_object = $(this).offset().left + $(this).outerWidth();
var center_of_window = $(window).scrollLeft() + $(window).width();
/* If the object is completely visible in the window, fade it it */
if (center_of_window > center_of_object) {
$(this).animate({
'opacity': '1'
}, 3000);
$(this).animate({
'bottom': '0'
}, 3500);
}
});
/* Reveal button delayed */
$('.button').each(function(i) {
var center_of_object = $(this).offset().left + $(this).outerWidth();
var center_of_window = $(window).scrollLeft() + $(window).width();
/* If the object is completely visible in the window, fade it it */
if (center_of_window > center_of_object) {
$(this).animate({
'opacity': '1'
}, 5000);
}
});
});
});
If your slide motion is animated fully (not incremental as it is in the jsfiddle you linked) then jQuery provides you with the ability to perform an action after your animation is complete.
http://api.jquery.com/animate/
Look at the options you can use for the animation function. One of them is called done. You can assign a function to the done option and that function will be called when your animation is complete.
Using one of your animates as an example, the syntax may look like this:
$(this).animate({
'opacity': '1'
}, {duration: 3000, done: function () {
//animate some stuff here
}};
Note that I just picked a random animation from your code. I'm not sure exactly when you want to perform the animation of the content, but you can use this technique anywhere you use a jQuery animate.
I've used this before to control nested animations in a slideshow format and it has worked very well! I hope this what you wanted.
I'm using the following javascript for the top of page logo/section before the footer here:
<div id="townEnd">InsideTown</div>
<script>
$(document).ready(function(){
// hide #townEnd first
$("#townEnd").hide();
// fade in #townEnd
$(function () {
$(window).scroll(function () {
if ($(this).scrollTop() > 1000) {
$('#townEnd').fadeIn();
} else {
$('#townEnd').fadeOut();
}
});
// scroll body to 0px on click
$('#townEnd a').click(function () {
$('body,html').animate({
scrollTop: 0
}, 800);
return false;
});
});
});
</script>
How would I calculate when the logo should fadein at the end of the page? I just used 1000 as an example. It only seems to work when I scroll really fast too.
First, you should just use this.scrollTop instead of $(this).scrollTop() - it might not look like much to you, but it is a HUGE thing.
On the same path, you can use this.scrollHeight to get the height of the scrollable area. Subtract this.innerHeight to get the maximum scroll position, then subtract about 30 pixels to give yourself some padding.
if( this.scrollTop < this.scrollHeight - this.innerHeight - 30)
You should also have a boolean to keep track of the state of the element, maybe isfadedin, which you update. Then, only call fadeIn and fadeOut if the state changes. This will save a LOT of processing time!
Vanilla JS is awesome :p
I am trying to get an fly-in / fly- out effect happening
Scroll down - animate in
Scroll-up animate out
To get a similar effect to the nizo website
http://nizoapp.com/
I have used this code I found on Stackoverflow "Fade in element on scroll down using css"
to determine whether the element is on screen, in the viewport, and then animate it.
$(window).scroll(function () {
/* Check the location of each desired element */
$('.article').each(function (i) {
var bottom_of_object = $(this).position().top + $(this).outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
/* If the object is completely visible in the window, fade it it */
if (bottom_of_window > bottom_of_object) {
$(this).animate({
'opacity': '1'
}, 500);
}
});
});
Which works quite well.
I have added it to this demo page, and modified it.
http://saigonhousefinder.com/potteryone/fadinonscroll.html
(probably not live for long)
I have used css transitions to get the effect I am looking for. FLy-in Fly-out etc etc
And then I found..... this function which does the same thing
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
Anyway.......
I cant get the animations to work when scrolling down, fly-in.
But I cannot get the animations to go in reverse when they fly out on scroll up
I thought the easiest way would be to detect if you are scrolling down of up, so I found this method / function
(function () {
var previousScroll = 0;
$(window).scroll(function () {
var currentScroll = $(this).scrollTop();
if (currentScroll > previousScroll){
$("#div").fadeIn("slow");
}
else {
$("#div").fadeOut("slow");
}
previousScroll = currentScroll;
});
}());
Which works well, but I cannot get it working.
At this point I can detect when an element is visible on the screen then add an effect to it.
What I need it to detect when that same element is beginning to go off the screen and apply another effect to it.
Any help on how to get this working would be great
Have a nice day
That's a really neat demo and a great concept! I played around with some code and it seems that you are almost there. You need to detect when the top of the screen meets the top of the element, so only calculate the offset once when the page is loaded. I added a 20px threshold so it kicks in a bit early. Let me know if this helps, it can be tweaked depending on how and when you want to call it. Here is a simple js fiddle demo
http://jsfiddle.net/XhAhR/23/
(function () {
var previousScroll = 0;
var elemTop = $("#div").offset().top;
$("#div").fadeOut();
$(window).scroll(function () {
var currentScroll = $(this).scrollTop();
if (currentScroll > previousScroll){
if(elemTop -20 > currentScroll){
$("#div").fadeIn("slow");
}
}
else {
if(elemTop - 20 > currentScroll){
$("#div").fadeOut("slow");
}
}
previousScroll = currentScroll;
});
}());
This is a follow-up post to a previous question: jQuery - scroll down every x seconds, then scroll to the top
I have refined the scrip a little further, but am having a little trouble with the last step.
I have a div that automatically 50px at a time until it reaches the bottom, at which point it scrolls to the top and starts again. I have this working perfectly thanks to the above question and with a little add work.
I need to make all scrolling stop when the div is hovered. I have done part of this already (there is no incremental scrolling down on hover) but I cannot get the full picture. The div will still scroll to the top even when hovered.
Here is my jQuery and a fiddle to go along with it: http://jsfiddle.net/wR5FY/1/
var scrollingUp = 0;
var dontScroll = 0;
window.setInterval(scrollit, 3000);
function scrollit() {
if(scrollingUp == 0 && dontScroll == 0) {
$('#scroller').animate({ scrollTop: $("#scroller").scrollTop() + 50 }, 'slow');
}
}
$('#scroller').bind('scroll', function () {
if (dontScroll == 0) {
if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
scrollingUp = 1;
$('#scroller').delay(2000).animate({ scrollTop: 0 }, 1000, function() {
scrollingUp = 0;
});
}
}
});
$('#scroller').bind('mouseenter', function() {
dontScroll = 1;
});
$('#scroller').bind('mouseleave', function() {
dontScroll = 0;
});
In the fiddle, try hovering the scroller div when the yellow square is visible. You will see that it scrolls to the top.
A couple of notes:
You will notice I have used mouseenter and mouseleave rather than hover and mouseout. This was the best way I could find to ensure all child elements within the div didn't have an adverse affect.
A potential problem area is the fact that I have binded to the scroll event for my function that scrolls to the top. I think this might cause some additional problems when a user is manually scrolling through the items, with my jQuery trying to scroll against the user.
I did a little experimenting with killing setInterval, but I didn't find this to be very helpful as the function that triggers isn't the problem area.
My overall goal here is to lock down all automatic scrolling when a user is hovering or manually scrolling through the list. This is 90% there. If they happen to scroll to the bottom, NOTHING should happen until they move the mouse elsewhere - this is the problem.
Keep it easier ;)
The problem was that you first evaluate wheter dontScroll is zero, then start the timer.
When the timer has ended, it doesnt evaluate anymore, whether dontScroll STILL is zero.
Just pulled that into your scrollIt function:
var scrollingUp = 0;
var dontScroll = 0;
window.setInterval(scrollit, 2000);
function scrollit() {
if(dontScroll == 0){
if ($('#scroller').scrollTop() + $('#scroller').innerHeight() >= $('#scroller')[0].scrollHeight) {
scrollingUp = 1;
$('#scroller').animate({ scrollTop: 0 }, 1000, function() {
scrollingUp = 0;
});
} else if(scrollingUp == 0) {
$('#scroller').animate({ scrollTop: $("#scroller").scrollTop() + 50 }, 'slow');
}
}
}
$('#scroller').bind('mouseenter', function() {
dontScroll = 1;
});
$('#scroller').bind('mouseleave', function() {
dontScroll = 0;
});