web-dev-qa-db-fra.com

Ouverture en fondu avec défilement vers le bas, fondu en sortie avec défilement vers le haut - basé sur la position de l'élément dans la fenêtre

J'essaie de faire défiler une série d'éléments quand ils sont entièrement visibles dans la fenêtre. Si je continue à faire défiler l'écran vers le bas, je ne veux pas qu'ils disparaissent progressivement, mais si je les fais défiler vers le haut, je veux qu'ils disparaissent progressivement.

C'est le jsfiddle le plus proche que j'ai trouvé . 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);

        }    
    }); 
}); 
});

Il fait exactement ce que je veux en faisant défiler l'écran vers le bas, mais je souhaite également que les éléments disparaissent progressivement si je les fais défiler.

J'ai essayé sans succès.

            if( bottom_of_window > bottom_of_object ){

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

            } else {

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

Merci beaucoup d'avoir pris le temps de regarder cela.

11
minimographite

Votre tentative n'a pas fonctionné parce que les deux animations (fondu en entrée et fondu en sortie) travaillaient l'une contre l'autre.

Juste avant qu'un objet ne devienne visible, il était toujours invisible et l'animation pour le fondu en boucle était exécutée. Ensuite, une fraction de seconde plus tard, lorsque ce même objet est devenu visible, l'animation en fondu à l'essai tenterait de s'exécuter, mais le fondu en cours était toujours actif. Ainsi, ils travailleraient les uns contre les autres et vous ne verriez rien.

Finalement, l'objet deviendrait visible (la plupart du temps), mais cela prendrait un certain temps. Et si vous vouliez faire défiler l'écran à l'aide du bouton en forme de flèche situé sur le bouton de la barre de défilement, l'animation fonctionnerait en quelque sorte, car vous feriez défiler avec des incréments plus importants, créant ainsi moins d'événements de défilement.


Assez d'explication, la solution (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/)

  • J'ai enveloppé le code de fondu dans une clause if: if ($(this).css("opacity")==0) {...}. Cela permet de s’assurer que l’objet n’est fondu que lorsque la opacity est 0. Il en va de même pour les évanouissements. Cela empêche les fades-in et fade-out de fonctionner l'un contre l'autre, car à présent, il n'y a plus qu'un seul des deux exécutant un objet à la fois.
  • J'ai changé .animate() en .fadeTo(). C'est la fonction spécialisée d'opacité de jQuery, beaucoup plus courte à écrire et probablement plus légère que l'animation.
  • J'ai changé .position() en .offset(). Ceci calcule toujours par rapport au corps, alors que la position est relative au parent. Pour votre cas, je pense que la compensation est la voie à suivre.
  • J'ai changé $(window).height() en $(window).innerHeight(). Ce dernier est plus fiable dans mon expérience.
  • Juste après le gestionnaire de défilement, j'appelle ce gestionnaire une fois au chargement de la page avec $(window).scroll();. Vous pouvez maintenant attribuer la classe .fade à tous les objets souhaités de la page, ainsi que les objets qui devraient être invisibles au chargement de la page, disparaître immédiatement.
  • J'ai supprimé #container de HTML et CSS, car (du moins pour cette réponse), ce n'est pas nécessaire. (Je pensais que vous aviez peut-être besoin du height:2000px parce que vous utilisiez .position() au lieu de .offset(), sinon je ne sais pas. N'hésitez pas à le laisser dans votre code.)

METTRE À JOUR

Si vous voulez des valeurs d'opacité autres que 0 et 1, utilisez le code suivant:

$(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>
(violon: http://jsfiddle.net/eLwex993/3/ )

  • J'ai ajouté un seuil à la clause if, voir explication ci-dessous.
  • J'ai créé des variables pour threshold et pour min/max au début de la fonction. Dans le reste de la fonction, ces variables sont référencées. De cette façon, si vous souhaitez modifier à nouveau les valeurs, vous ne devez le faire qu’à un seul endroit.
  • J'ai également ajouté || pageLoad à la clause if. Cela était nécessaire pour s'assurer que tous les objets sont fondus à l'opacité correcte lors du chargement de la page. pageLoad est un booléen qui est envoyé en tant qu'argument lorsque fade() est appelé.
    Je devais mettre le code de fondu à l'intérieur de la function fade() {...} supplémentaire afin de pouvoir envoyer le booléen pageLoad lorsque le gestionnaire de défilement est appelé.
    Je n'ai pas vu d'autre moyen de faire cela, si quelqu'un d'autre le fait, s'il vous plaît laissez un commentaire.

Explication:
La raison pour laquelle le code dans votre violon - n'a pas fonctionné, c'est parce que les valeurs d'opacité réelles sont toujours légèrement différentes de celles que vous avez définies. Ainsi, si vous définissez l'opacité sur 0.3, la valeur réelle (dans ce cas) est 0.300000011920929. C'est juste un de ces petits bugs que vous devez apprendre le long du chemin par piste et par erreur. C'est pourquoi cette clause if ne fonctionnera pas: if ($(this).css("opacity") == 0.3) {...}.

J'ai ajouté un seuil pour prendre en compte cette différence: == 0.3 devient <= 0.31.
(J'ai défini le seuil sur 0.01, cela peut être modifié bien sûr, aussi longtemps que l'opacité réelle se situera entre la valeur définie et ce seuil.)}

Les opérateurs sont maintenant passés de == à <= et >=.


MISE À JOUR 2:

Si vous souhaitez atténuer les éléments en fonction de leur pourcentage visible, utilisez le code suivant:

$(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>
(violon: http://jsfiddle.net/eLwex993/5/ )

37
myfunkyside

J'ai légèrement modifié votre code pour le rendre plus robuste. En termes d'amélioration progressive, il est probablement préférable d'avoir toute la logique de fondu en fondu en JavaScript. Dans l'exemple de myfunksyde, tout utilisateur sans JavaScript ne voit rien à cause du 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();});
});

Voir ici: http://jsfiddle.net/78xjLnu1/16/

Cordialement, Martin

3
hobbeshunter

Je sais qu'il est tard, mais je prends le code original et change quelques éléments pour contrôler facilement les fichiers CSS. J'ai donc créé un code avec addClass () et removeClass ()

Voici le code complet: 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');
3
Michael Deleau

Désolé, c'est du vieux fil, mais certaines personnes en auraient encore besoin, je suppose,

Note: J'ai réalisé ceci en utilisant la bibliothèque Animate.css pour animer le fondu.

J'ai utilisé votre code et ajouté simplement la classe .hidden (à l'aide de la classe cachée de bootstrap), mais vous pouvez toujours définir .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');
               }

}); 
}); 
});

Autre remarque: L’application de cette option sur les conteneurs peut entraîner une dégradation de l’ordre.

0
Valumin