The reason your attempt wasn't working, is because the two animations (fade-in and fade-out) were working against each other.
Right before an object became visible, it was still invisible and so the animation for fading-out would run. Then, the fraction of a second later when that same object had become visible, the fade-in animation would try to run, but the fade-out was still running. So they would work against each other and you would see nothing.
Eventually the object would become visible (most of the time), but it would take a while. And if you would scroll down by using the arrow-button at the button of the scrollbar, the animation would sort of work, because you would scroll using bigger increments, creating less scroll-events.
Enough explanation, the solution (JS, CSS, HTML):
$(window).on("load",function() {_x000D_
$(window).scroll(function() {_x000D_
var windowBottom = $(this).scrollTop() + $(this).innerHeight();_x000D_
$(".fade").each(function() {_x000D_
/* Check the location of each desired element */_x000D_
var objectBottom = $(this).offset().top + $(this).outerHeight();_x000D_
_x000D_
/* If the element is completely within bounds of the window, fade it in */_x000D_
if (objectBottom < windowBottom) { //object comes into view (scrolling down)_x000D_
if ($(this).css("opacity")==0) {$(this).fadeTo(500,1);}_x000D_
} else { //object goes out of view (scrolling up)_x000D_
if ($(this).css("opacity")==1) {$(this).fadeTo(500,0);}_x000D_
}_x000D_
});_x000D_
}).scroll(); //invoke scroll-handler on page-load_x000D_
});
_x000D_
.fade {_x000D_
margin: 50px;_x000D_
padding: 50px;_x000D_
background-color: lightgreen;_x000D_
opacity: 1;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>_x000D_
_x000D_
<div>_x000D_
<div class="fade">Fade In 01</div>_x000D_
<div class="fade">Fade In 02</div>_x000D_
<div class="fade">Fade In 03</div>_x000D_
<div class="fade">Fade In 04</div>_x000D_
<div class="fade">Fade In 05</div>_x000D_
<div class="fade">Fade In 06</div>_x000D_
<div class="fade">Fade In 07</div>_x000D_
<div class="fade">Fade In 08</div>_x000D_
<div class="fade">Fade In 09</div>_x000D_
<div class="fade">Fade In 10</div>_x000D_
</div>
_x000D_
if ($(this).css("opacity")==0) {...}
. This makes sure the object is only faded in when the opacity
is 0
. Same goes for fading out. And this prevents the fade-in and fade-out from working against each other, because now there's ever only one of the two running at one time on an object..animate()
to .fadeTo()
. It's jQuery's specialized function for opacity, a lot shorter to write and probably lighter than animate..position()
to .offset()
. This always calculates relative to the body, whereas position is relative to the parent. For your case I believe offset is the way to go.$(window).height()
to $(window).innerHeight()
. The latter is more reliable in my experience.$(window).scroll();
. Now you can give all desired objects on the page the .fade
class, and objects that should be invisible at page-load, will be faded out immediately.#container
from both HTML and CSS, because (at least for this answer) it isn't necessary. (I thought maybe you needed the height:2000px
because you used .position()
instead of .offset()
, otherwise I don't know. Feel free of course to leave it in your code.)If you want opacity values other than 0
and 1
, use the following code:
$(window).on("load",function() {_x000D_
function fade(pageLoad) {_x000D_
var windowBottom = $(window).scrollTop() + $(window).innerHeight();_x000D_
var min = 0.3;_x000D_
var max = 0.7;_x000D_
var threshold = 0.01;_x000D_
_x000D_
$(".fade").each(function() {_x000D_
/* Check the location of each desired element */_x000D_
var objectBottom = $(this).offset().top + $(this).outerHeight();_x000D_
_x000D_
/* If the element is completely within bounds of the window, fade it in */_x000D_
if (objectBottom < windowBottom) { //object comes into view (scrolling down)_x000D_
if ($(this).css("opacity")<=min+threshold || pageLoad) {$(this).fadeTo(500,max);}_x000D_
} else { //object goes out of view (scrolling up)_x000D_
if ($(this).css("opacity")>=max-threshold || pageLoad) {$(this).fadeTo(500,min);}_x000D_
}_x000D_
});_x000D_
} fade(true); //fade elements on page-load_x000D_
$(window).scroll(function(){fade(false);}); //fade elements on scroll_x000D_
});
_x000D_
.fade {_x000D_
margin: 50px;_x000D_
padding: 50px;_x000D_
background-color: lightgreen;_x000D_
opacity: 1;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>_x000D_
_x000D_
<div>_x000D_
<div class="fade">Fade In 01</div>_x000D_
<div class="fade">Fade In 02</div>_x000D_
<div class="fade">Fade In 03</div>_x000D_
<div class="fade">Fade In 04</div>_x000D_
<div class="fade">Fade In 05</div>_x000D_
<div class="fade">Fade In 06</div>_x000D_
<div class="fade">Fade In 07</div>_x000D_
<div class="fade">Fade In 08</div>_x000D_
<div class="fade">Fade In 09</div>_x000D_
<div class="fade">Fade In 10</div>_x000D_
</div>
_x000D_
threshold
and for min/max
at the start of the function. In the rest of the function these variables are referenced. This way, if you ever want to change the values again, you only have to do it in one place.|| pageLoad
to the if-clause. This was necessary to make sure all objects are faded to the correct opacity on page-load. pageLoad
is a boolean that is send along as an argument when fade()
is invoked.function fade() {...}
, in order to be able to send along the pageLoad
boolean when the scroll-handler is invoked.Explanation:
The reason the code in your fiddle didn't work, is because the actual opacity values are always a little off from the value you set it to. So if you set the opacity to 0.3
, the actual value (in this case) is 0.300000011920929
. That's just one of those little bugs you have to learn along the way by trail and error. That's why this if-clause won't work: if ($(this).css("opacity") == 0.3) {...}
.
I added a threshold, to take that difference into account: == 0.3
becomes <= 0.31
.
(I've set the threshold to 0.01
, this can be changed of course, just as long as the actual opacity will fall between the set value and this threshold.)
The operators are now changed from ==
to <=
and >=
.
If you want to fade the elements based on their visible percentage, use the following code:
$(window).on("load",function() {_x000D_
function fade(pageLoad) {_x000D_
var windowTop=$(window).scrollTop(), windowBottom=windowTop+$(window).innerHeight();_x000D_
var min=0.3, max=0.7, threshold=0.01;_x000D_
_x000D_
$(".fade").each(function() {_x000D_
/* Check the location of each desired element */_x000D_
var objectHeight=$(this).outerHeight(), objectTop=$(this).offset().top, objectBottom=$(this).offset().top+objectHeight;_x000D_
_x000D_
/* Fade element in/out based on its visible percentage */_x000D_
if (objectTop < windowTop) {_x000D_
if (objectBottom > windowTop) {$(this).fadeTo(0,min+((max-min)*((objectBottom-windowTop)/objectHeight)));}_x000D_
else if ($(this).css("opacity")>=min+threshold || pageLoad) {$(this).fadeTo(0,min);}_x000D_
} else if (objectBottom > windowBottom) {_x000D_
if (objectTop < windowBottom) {$(this).fadeTo(0,min+((max-min)*((windowBottom-objectTop)/objectHeight)));}_x000D_
else if ($(this).css("opacity")>=min+threshold || pageLoad) {$(this).fadeTo(0,min);}_x000D_
} else if ($(this).css("opacity")<=max-threshold || pageLoad) {$(this).fadeTo(0,max);}_x000D_
});_x000D_
} fade(true); //fade elements on page-load_x000D_
$(window).scroll(function(){fade(false);}); //fade elements on scroll_x000D_
});
_x000D_
.fade {_x000D_
margin: 50px;_x000D_
padding: 50px;_x000D_
background-color: lightgreen;_x000D_
opacity: 1;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>_x000D_
_x000D_
<div>_x000D_
<div class="fade">Fade In 01</div>_x000D_
<div class="fade">Fade In 02</div>_x000D_
<div class="fade">Fade In 03</div>_x000D_
<div class="fade">Fade In 04</div>_x000D_
<div class="fade">Fade In 05</div>_x000D_
<div class="fade">Fade In 06</div>_x000D_
<div class="fade">Fade In 07</div>_x000D_
<div class="fade">Fade In 08</div>_x000D_
<div class="fade">Fade In 09</div>_x000D_
<div class="fade">Fade In 10</div>_x000D_
</div>
_x000D_