向下滚动时淡入,向上滚动时淡出 - 基于窗口中元素位置。

23

我想让一系列元素在完全可见时淡入,当向下滚动时。如果我继续向下滚动,我不希望它们淡出,但如果我向上滚动,我确实希望它们淡出。

这是我找到的最接近的jsfiddle。 http://jsfiddle.net/tcloninger/e5qaD/

$(document).ready(function() {

/* Every time the window is scrolled ... */
$(window).scroll( function(){

    /* Check the location of each desired element */
    $('.hideme').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);

        }    
    }); 
}); 
});

在向下滚动时,它做的正是我想要的,但如果我向上滚过它们,我也希望元素淡出。

我尝试过这个,但没有成功。

            if( bottom_of_window > bottom_of_object ){

                $(this).animate({'opacity':'1'},500);  

            } else {

               $(this).animate({'opacity':'0'},500); }
感谢您抽出时间查看这个内容。
4个回答

71

你的代码没有生效的原因是两个动画(淡入和淡出)相互抵消了。

在一个对象变得可见之前,它仍然是不可见的,所以淡出动画会运行。然后,在同一对象变得可见的几分之一秒后,淡入动画会尝试运行,但淡出仍在运行。它们会相互抵消,你将看不到任何东西。

最终,对象会变得可见(大多数情况下),但需要一段时间。如果使用滚动条底部的箭头按钮向下滚动,则动画会有所作用,因为滚动使用较大的增量,创建较少的滚动事件。


解决方案(JS,CSS,HTML):

$(window).on("load",function() {
  $(window).scroll(function() {
    var windowBottom = $(this).scrollTop() + $(this).innerHeight();
    $(".fade").each(function() {
      /* Check the location of each desired element */
      var objectBottom = $(this).offset().top + $(this).outerHeight();
      
      /* If the element is completely within bounds of the window, fade it in */
      if (objectBottom < windowBottom) { //object comes into view (scrolling down)
        if ($(this).css("opacity")==0) {$(this).fadeTo(500,1);}
      } else { //object goes out of view (scrolling up)
        if ($(this).css("opacity")==1) {$(this).fadeTo(500,0);}
      }
    });
  }).scroll(); //invoke scroll-handler on page-load
});
.fade {
  margin: 50px;
  padding: 50px;
  background-color: lightgreen;
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

<div>
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</div>
</div>

(fiddle: http://jsfiddle.net/eLwex993/2/)

  • 我在一个if语句中封装了fade-codeline:if ($(this).css("opacity")==0) {...}。这样可以确保对象只在opacity0时才会淡入。淡出也是一样。这可以防止淡入和淡出相互作用,因为现在只有其中一个在对象上运行。
  • 我将.animate()更改为.fadeTo()。它是jQuery专门针对不透明度的函数,写起来更简短,而且可能比animate更轻量级。
  • 我将.position()更改为.offset()。它总是相对于body进行计算,而position是相对于父元素。在您的情况下,我认为offset是更好的选择。
  • 我将$(window).height()更改为$(window).innerHeight()。根据我的经验,后者更可靠。
  • 在滚动处理程序之后,我使用$(window).scroll();在页面加载时立即调用该处理程序。现在,您可以为页面上的所有需要的对象添加.fade类,并且应在页面加载时淡出不可见的对象。
  • 我从HTML和CSS中删除了#container,因为(至少对于这个答案)它不是必要的。(我想也许您需要height:2000px,因为您使用了.position()而不是.offset(),否则我不知道。当然,您可以在您的代码中保留它。)

更新

如果您想要除01以外的其他不透明度值,请使用以下代码:

$(window).on("load",function() {
  function fade(pageLoad) {
    var windowBottom = $(window).scrollTop() + $(window).innerHeight();
    var min = 0.3;
    var max = 0.7;
    var threshold = 0.01;
    
    $(".fade").each(function() {
      /* Check the location of each desired element */
      var objectBottom = $(this).offset().top + $(this).outerHeight();
      
      /* If the element is completely within bounds of the window, fade it in */
      if (objectBottom < windowBottom) { //object comes into view (scrolling down)
        if ($(this).css("opacity")<=min+threshold || pageLoad) {$(this).fadeTo(500,max);}
      } else { //object goes out of view (scrolling up)
        if ($(this).css("opacity")>=max-threshold || pageLoad) {$(this).fadeTo(500,min);}
      }
    });
  } fade(true); //fade elements on page-load
  $(window).scroll(function(){fade(false);}); //fade elements on scroll
});
.fade {
  margin: 50px;
  padding: 50px;
  background-color: lightgreen;
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

<div>
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</div>
</div>

(fiddle: http://jsfiddle.net/eLwex993/3/)

  • 我在if语句中添加了一个阈值,见下面的解释
  • 我在函数开头创建了变量thresholdmin/max。在函数的其余部分中,这些变量被引用。这样,如果您想要再次更改这些值,您只需要在一个地方进行更改。
  • 我还在if语句中添加了|| pageLoad。这是必要的,以确保所有对象在页面加载时都会淡入到正确的不透明度。pageLoad是一个布尔值,当调用fade()时作为参数发送。
    我不得不将淡入代码放在额外的function fade() {...}内,以便在滚动处理程序被调用时能够同时发送pageLoad布尔值。
    如果有其他方法,欢迎留言。

解释:
你的示例中,代码无法正常工作的原因是实际不透明度值总是略微偏离设置的值。因此,如果您将不透明度设置为0.3,实际值(在这种情况下)为0.300000011920929。这是你必须通过试错学习的那些小错误之一。这就是为什么这个if语句不起作用:if ($(this).css("opacity") == 0.3) {...}

我添加了一个阈值,以考虑到这种差异:==0.3变成了<=0.31
(我将阈值设置为0.01,当然可以更改,只要实际不透明度将落在设置值和此阈值之间即可。)

操作符现在从==变成了<=>=


更新2:

如果您想根据元素的可见百分比淡入,请使用以下代码:

$(window).on("load",function() {
  function fade(pageLoad) {
    var windowTop=$(window).scrollTop(), windowBottom=windowTop+$(window).innerHeight();
    var min=0.3, max=0.7, threshold=0.01;
    
    $(".fade").each(function() {
      /* Check the location of each desired element */
      var objectHeight=$(this).outerHeight(), objectTop=$(this).offset().top, objectBottom=$(this).offset().top+objectHeight;
      
      /* Fade element in/out based on its visible percentage */
      if (objectTop < windowTop) {
        if (objectBottom > windowTop) {$(this).fadeTo(0,min+((max-min)*((objectBottom-windowTop)/objectHeight)));}
        else if ($(this).css("opacity")>=min+threshold || pageLoad) {$(this).fadeTo(0,min);}
      } else if (objectBottom > windowBottom) {
        if (objectTop < windowBottom) {$(this).fadeTo(0,min+((max-min)*((windowBottom-objectTop)/objectHeight)));}
        else if ($(this).css("opacity")>=min+threshold || pageLoad) {$(this).fadeTo(0,min);}
      } else if ($(this).css("opacity")<=max-threshold || pageLoad) {$(this).fadeTo(0,max);}
    });
  } fade(true); //fade elements on page-load
  $(window).scroll(function(){fade(false);}); //fade elements on scroll
});
.fade {
  margin: 50px;
  padding: 50px;
  background-color: lightgreen;
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

<div>
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</div>
</div>

(fiddle: http://jsfiddle.net/eLwex993/5/)


@minimographite - 我在我的答案中添加了一个更新,用于除 01 以外的其他不透明度值。感谢您的赞赏,这总是会让海报感到高兴的! - myfunkyside
@CamrinParnell - 我认为我会将行中每个元素的ID放入一个数组中,然后在for循环中遍历该数组中的每个元素,对每个元素使用fadeTo()函数,但使用更短的淡出时间。 - myfunkyside
1
@sm.ali 你的代码可能有两个问题阻止了它的工作。 1) 确保给你的页脚添加 fade 类,因为这段代码只适用于具有该类的元素。 2)if (objectBottom < windowBottom) { 更改为 if (objectBottom <= windowBottom) {;因为你的页脚(可能)固定在页面底部,页脚底部永远不会小于窗口底部。通过将 < 更改为 <=,当页脚底部等于窗口底部时,代码也将起作用。或者,您可以使用 objectTop 来创建更好的效果,我将把这留给您决定。 - myfunkyside
嘿,我遇到了一个问题,在页面加载时,所有内容都是完全不透明的,但是一旦滚动,正确的淡入淡出就会发生。你有什么建议吗? - irahorecka
1
@myfunkyside 更新2是非常好的答案!我想指出,在代码的第三行,您可以为窗口边框添加“padding”,例如,windowTop+=150,windowBottom-=300。这将延迟fadeIn,直到.fade元素更靠近屏幕中央。 - Jim22150
显示剩余3条评论

6

我稍微修改了你的代码,并使其更加健壮。从渐进增强的角度来看,最好将所有淡入淡出逻辑放在JavaScript中。在myfunksyde的示例中,任何没有JavaScript的用户都看不到任何东西,因为有opacity: 0;

    $(window).on("load",function() {
    function fade() {
        var animation_height = $(window).innerHeight() * 0.25;
        var ratio = Math.round( (1 / animation_height) * 10000 ) / 10000;

        $('.fade').each(function() {

            var objectTop = $(this).offset().top;
            var windowBottom = $(window).scrollTop() + $(window).innerHeight();

            if ( objectTop < windowBottom ) {
                if ( objectTop < windowBottom - animation_height ) {
                    $(this).html( 'fully visible' );
                    $(this).css( {
                        transition: 'opacity 0.1s linear',
                        opacity: 1
                    } );

                } else {
                    $(this).html( 'fading in/out' );
                    $(this).css( {
                        transition: 'opacity 0.25s linear',
                        opacity: (windowBottom - objectTop) * ratio
                    } );
                }
            } else {
                $(this).html( 'not visible' );
                $(this).css( 'opacity', 0 );
            }
        });
    }
    $('.fade').css( 'opacity', 0 );
    fade();
    $(window).scroll(function() {fade();});
});

点击这里查看:http://jsfiddle.net/78xjLnu1/16/

祝好, 马丁


关于非JavaScript用户的问题,你说得很好。我非常喜欢你的回答 :) - myfunkyside

4
我知道现在已经很晚了,但我拿到了原始代码并进行了一些更改以便更容易地控制CSS。因此,我使用了addClass()和removeClass()方法编写了代码。
以下是完整的代码:http://jsfiddle.net/e5qaD/4837/
        if( bottom_of_window > bottom_of_object ){
            $(this).addClass('showme');
       }
        if( bottom_of_window < bottom_of_object ){
            $(this).removeClass('showme');

我喜欢这个选项的效果更好!如何将bottom_of_object更改为在底部的顶部? - Marco Romano
只需要很少的代码就能完美运行。我将其添加到我的作品集网站上,以淡入淡出元素。如果使用过渡属性来平滑滚动淡入,效果会更好。 - Chetan Nada

0

抱歉,这是一个旧帖子,但我想仍有些人需要它。

注意:我使用Animate.css库实现了渐隐动画。

我使用了您的代码,并添加了.hidden类(使用Bootstrap的hidden类),但您仍可以定义.hidden { opacity: 0; }

$(document).ready(function() {

/* Every time the window is scrolled ... */

$(window).scroll( function(){

/* Check the location of each desired element */
$('.hideme').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).removeClass('hidden');
        $(this).addClass('animated fadeInUp');
    }    else {
            $(this).addClass('hidden');
               }

}); 
}); 
});

另外注意:将此应用于容器可能会导致其出现故障。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接