IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

jQuery Discussion :

Scroller la page de la hauteur d'un élément pour qu'il soit entièrement visible


Sujet :

jQuery

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    50
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 50
    Points : 19
    Points
    19
    Par défaut Scroller la page de la hauteur d'un élément pour qu'il soit entièrement visible
    Bonjour,

    Tout près du but, j'aurais bien besoin d'un coup de main !
    Classique : j'essaye de combiner 2 actions JQuery qui fonctionnent très bien séparément :

    1/ un slideUp / slideDown sous condition de visibilité (onClick):
    https://codepen.io/Webdee/pen/WyrmXE

    2/ scroller la page de la hauteur d'un élément pour qu'il soit entièrement visible dans la fenêtre du navigateur (onLoad ds l'exemple):
    https://codepen.io/Webdee/pen/yEerzW

    Mais quand je tente de combiner les 2 (en ajoutant la hauteur du bouton de l'élément), ça marche nickel pour le 1er BT/elemt, mais moyen bof pour les suivants : Le scroll s'opère bien, mais sans aller jusqu'en bas de l'élément pour les textes 2 et 3 :
    https://codepen.io/Webdee/pen/jKWJpZ

    J'avoue que les raisonnements mathématiques ne sont pas mon fort, et du coup là, je sèche.
    Un œil extérieur avisé serait le bienvenu !…

  2. #2
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    J'ai pas été regarder en détail ton code, mais je n'y ai vu aucune gestion de promesses dedans alors que c'est incontournable dans ce cas.

    => https://developer.mozilla.org/fr/doc..._les_promesses

    le scroll ou l'ouverture "slideDown" se font tout 2 en asynchrone, en clair ça veut dire qu'il n'attend pas que la première opération soit terminée pour faire la seconde; et cette seconde opération se fait donc avec des paramètres de positionnement qui sont antérieurs
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  3. #3
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    16 959
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 16 959
    Points : 44 122
    Points
    44 122
    Par défaut
    Bonjour,
    c'est plus une question d'enchainement qu'une question de mathématiques

    Il te faut utiliser une fonction « callback » qui s'exécute une fois l'animation terminée. (.slideUp())
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $( "#id-element" ).slideUp( "slow", function() {
      // Animation complete.
    });
    Voilà ce que cela pourrait donner en séquençant les animations.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    $(".js-click").on("click", function() {
     
      function scrollToBottom($elem) {
        // ouverture élément
        $elem.slideDown(speedAnimation, function() {
          // récup. des positions/dimensions
          var bodyScrollTop = $("body").scrollTop();
          var winBottom = $(window).height() + bodyScrollTop;
          var elemBottom = $elem.offset().top + $elem.outerHeight(true);
          var decalage = elemBottom - winBottom;      
          // lance le scroll si besoin
          if (decalage > 0) {      
            $("html, body").animate({
              scrollTop: (bodyScrollTop + decalage)
            }, "slow");
          }
        });
      }
     
      var speedAnimation = 200;
      // récup. élément concerné
      var $nextElement = $(this).next(".content");
      // si l'élément est caché
      if ($nextElement.is(":hidden")) {
        // si un élément est visible encours on le masque
        // et on ouvre le suivant
        var $elemEnCours = $(".content:visible");
        if ($elemEnCours.length) {
          $elemEnCours.slideUp(speedAnimation, function() {
            scrollToBottom($nextElement)
          });
        }
        // sinon on ouvre directement
        else {
          scrollToBottom($nextElement);
        }
      }
      else {
        $($nextElement).slideUp(speedAnimation);
      }
    });
    Si tu souhaites faire la fermeture et l'ouverture en même temps, l'approche est différente et il te faut récupérer la hauteur de l'élément visible en cours pour en tenir compte dans le décalage.

    Attention : Ton animation pique un peu les yeux et ergonomiquement parlant ce n'est pas le top, tu obliges le visiteur à faire un scrollUP après ouverture de l'article pour en lire le début si il ne tiens pas dans la fenêtre.


    [EDIT] le code de la fonction scrollToBottom est incorrecte voir la correction au post #6.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    50
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 50
    Points : 19
    Points
    19
    Par défaut
    Merci NoSmoking !

    En fait c'est plutôt la logique mathématique qui me fait parfois défaut (et des connaissances plus approfondies en JS).

    Concernant ta mise en garde, pas de souci, j'ai pris du texte comme exemple de contenu variable en taille, mais il s'agit en fait de vidéos dans un conteneur extensible; je voulais être sûre qu'on pouvait paramétrer un scroll de la hauteur de l'élément, même si sa hauteur n'était pas spécifiée dans le css. Vu la taille max d'une vidéo (puisqu'elles n'apparaissent qu'une par une) le haut de l'écran ne risque pas d'être caché après le scroll.

    Merci encore pour ton exemple de code commenté (que je vais essayer d'analyser et de comprendre en détail) !!!

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    50
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 50
    Points : 19
    Points
    19
    Par défaut
    En fait, je ne m'en sors toujours pas :

    - Au click, si le bas de l'élément est caché sous le bord inférieur de la fenêtre du navigateur : la page scrolle vers le bas pour qu'il soit visible en entier : OK.
    - Mais si tout va bien et qu'il y a l'espace suffisant pour que l'élément soit visible (par ex : si l'utilisateur a scrollé la page avant de cliquer) : la page scrolle tout de même et remonte pour caler le bas du contenu au ras du bas de la page… Alors que dans mon idée, le scroll ne devait se déclencher que si le bas de l'élément était caché.
    Et c'est la ou la logique me manque, car je n'arrive pas à modifier la condition du slideDown pour parvenir à ce résultat.

    Il y a un autre détail, comme mon élément contient une iframe youtube, j'avais une portion de code à ajouter après chaque slideUp pour supprimer puis restaurer l'url de l'iframe (pour que la video ne continue pas à jouer une fois cachée, et que l'iframe soit néanmoins prête à re-servir si nécessaire):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $(this).next(".content iframe").attr('src', '');
    $(this).next(".content iframe").attr('src', url);
    et là, la structure est plus complexe et je n'arrive pas à l'insérer correctement dans la fonction qui gère le slideUp… La 1ère ligne de code fonctionne, mais la 2e n'est pas prise en compte et l'écran reste vide si on re-clique pour voir la video.
    Même en répartissant ces 2 lignes entre le slideUp et le slideDown ça ne fonctionne pas.

  6. #6
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    16 959
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 16 959
    Points : 44 122
    Points
    44 122
    Par défaut
    j'ai utilisé comme base ton code sans voir qu'il ne fallait pas utiliser $("body").scrollTop() mais $(window).scrollTop().

    La fonction, scrollToBottom, corrigée donne donc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
      function scrollToBottom($elem) {
        // ouverture élément
        $elem.slideDown(speedAnimation, function() {
          // récup. des positions/dimensions
          var winScrollTop = $(window).scrollTop(); // et NON $("body").scrollTop();
          var winBottom = $(window).height() + winScrollTop;
          var elemBottom = $elem.offset().top + $elem.outerHeight(true);
          var decalage = elemBottom - winBottom;
          // lance le scroll si besoin
          if (decalage > 0) {
            $("html, body").animate({
              scrollTop: (winScrollTop + decalage)
            }, "slow");
          }
        });
      }

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    50
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 50
    Points : 19
    Points
    19
    Par défaut
    Fantastique ! J'ai essayé de reformuler le calcul différemment alors qu'il suffisait d'un mot ! Mais 1 mot qui change tout !
    Merci 1000 fois !

    Et pour le code concernant l'iframe que j'avais inséré après mon slideUp, tu saurais à quelle étape je peux l'insérer pour qu'il fonctionne avec ton code ? Je dois dire que je n'utilise en général que des fonctions jQuery très simples, et là j'ai beau essayer, je ne maitrise pas tout.

    Avec ma fonction un peu simplette (ci-dessous), ça marchait super, mais là j'ai essayé plusieurs options sans succès.
    La classe '.video' remplace ici la classe '.content' de l'exemple que j'ai mis en ligne sur codepen.
    Sans le pb du scroll j'ai :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    $(".js-click").on("click", function(){
     
    	var ecran = $(this).next(".video"); // video qui suit le bt sur lequel on clique
    	var iframeYT = $('.video:visible iframe');
    	var url = $(iframeYT).attr('src');
     
    	if ( ecran.is( ":hidden" ) ) {
    		$(".video:visible").slideUp(200); // referme les autres videos visibles
    		$(iframeYT).attr('src', ''); // supprime l'url active de l'iframe visible (qu'on vient de refermer)
    		$(iframeYT).attr('src', url); // restaure l'url de l'iframe visible pour utilisations ultérieures
    		$( ecran ).slideDown(200);
     
      	} else {
        	$( ecran ).slideUp(200);  // referme la video qu'on vient d'ouvrir
    		$(iframeYT).attr('src', ''); // supprime l'url active de l'iframe visible (qu'on vient de refermer)
    		$(iframeYT).attr('src', url); // restaure l'url de l'iframe visible pour utilisations ultérieures
      	}
     
    })
    Mais avec ton code, ça ne marche plus…

  8. #8
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 740
    Points
    4 740
    Par défaut
    Dans la doc jQuery : .slideUp( [duration ] [, complete ] ),

    le complete est l'élément que tu dois prendre ne compte = il permet d'y placer le le code de ton choix, une fois que le slideUp ce soit achevé.
    on appelle aussi cette partie une fonction CallBack (cf NoSmoking).

    c'est un peu comme si tu donnais comme suite d'instructions :
    1- Lancer le Frisbee
    2- repeindre le Frisbee en vert
    ce qui est impossible à faire car personne ne peut peindre un Frisbee alors qui est en train de voler dans les airs.

    Comme je te l'ai écrit plus haut, la fonction slideUp est a ranger dans la catégorie des fonctions asynchrones, et le langage JavaScript n'attends pas qu'une fonction asynchrone se soit terminée pour passer aux instructions suivantes.

    Pour utiliser la fonction CallBack faut écrire
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $( ecran ).slideUp(200, function() {    // referme la video qu'on vient d'ouvrir
     
      // code à exécuter une fois que l'interpréteur JavaScript à réalisé le fermeture de la vidéo = partie CallBack
     
      $(iframeYT).attr('src', ''); // supprime l'url active de l'iframe visible (qu'on vient de refermer)
      $(iframeYT).attr('src', url); // restaure l'url de l'iframe visible pour utilisations ultérieures
     
    });
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    50
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 50
    Points : 19
    Points
    19
    Par défaut
    Merci à vous 2,
    grâce à vous je pense avoir un peu avancé sur cette histoire de callback, sans doute de manière plus empirique que mathématique
    J'ai finalement repris mon code et découpé la fonction d'une manière qui me semble plus facile à comprendre et me permet d'insérer mon "vidéo killer" au slideUp et la fonction de scroll (perfectionnée par NoSmoking) au slideDown avec le système de callback :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    $(".ruban-click").on("click", function(){
     
          function scrollToBottom($elem) {
          // récup. des positions/dimensions
          var winScrollTop = $(window).scrollTop();
          var winBottom = $(window).height() + winScrollTop;
          var elemBottom = $elem.offset().top + $elem.outerHeight(true);
          var decalage = elemBottom - winBottom;      
          // lance le scroll si besoin
          if (decalage > 0) {      
            $("html, body").animate({
              scrollTop: (winScrollTop + decalage)
            }, "slow");
          }
      }
     
    	var ecran = $(this).next(".video"); // video du bt sur lequel on clique
    	var iframeYT = $('.video:visible iframe');
    	var url = $(iframeYT).attr('src');
     
     
    	if ( ecran.is( ":hidden" ) ) {
    		$(".video:visible").slideUp(200); // referme l'autre video visible
    		$(iframeYT).attr('src', ''); // supprime l'url active de l'iframe visible
    		$(iframeYT).attr('src', url); // restaure l'url de l'iframe visible pour utilisations ultérieures
    		// ouvre la video du bt ET lance le scroll si besoin
    		$( ecran ).slideDown(200, function() {
    		scrollToBottom(ecran);
    		});
     
     
      	} else {
        	$( ecran ).slideUp(200);
    	$(iframeYT).attr('src', '');
    	$(iframeYT).attr('src', url);
      	}
     
    })
    Merci encore d'avoir pris le temps de vous pencher sur mon problème. C'est bon quand les brumes se dissipent et que ça marche enfin !!

  10. #10
    Rédacteur/Modérateur

    Avatar de SpaceFrog
    Homme Profil pro
    Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Inscrit en
    Mars 2002
    Messages
    39 637
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2002
    Messages : 39 637
    Points : 66 658
    Points
    66 658
    Billets dans le blog
    1
    Par défaut
    Je ne sais pas si ça serait utile dans ton cas de figure, mais il m'est arrivé par le passé d'utiliser scrollIntoView
    Ma page Developpez - Mon Blog Developpez
    Président du CCMPTP (Comité Contre le Mot "Problème" dans les Titres de Posts)
    Deux règles du succès: 1) Ne communiquez jamais à quelqu'un tout votre savoir...
    Votre post est résolu ? Alors n'oubliez pas le Tag

    Venez sur le Chat de Développez !

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    50
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 50
    Points : 19
    Points
    19
    Par défaut
    Intéressant, merci pour le tuyau ! je ne connaissais pas.
    Mais la compatibilité IE n'a pas l'air top.

  12. #12
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    16 959
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 16 959
    Points : 44 122
    Points
    44 122
    Par défaut
    Mais la compatibilité IE n'a pas l'air top.
    Euh c'est reconnu depuis IE8 alors !!!

    Il est vrai que si tu veux la possibilité d'utiliser les options et notamment oElem.scrollIntoView({behavior: 'smooth'}) il va te falloir continuer à passer par un effet/animation.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Mise en page xhtml/css : hauteur de colone.
    Par Angelfr83 dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 15/02/2010, 21h44
  2. Scroller une page dans une autre fenêtre
    Par lefaucheur dans le forum Débuter
    Réponses: 4
    Dernier message: 27/08/2009, 16h29
  3. Scroller dans page php
    Par zorrax dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 27/02/2009, 17h18
  4. Réponses: 2
    Dernier message: 10/07/2008, 14h43
  5. Faire scroller une page de x pixels au chargement ?
    Par guidav dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 16/07/2007, 17h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo