11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous
Je n'arrive pas à trouver d'explication très claire sur la façon de faire défiler "scroller" un élément contenu dans une <div> avec ascenseur overflow:auto, par exemple:

<div id="container" style="overflow:auto;height:5em;">
    <ul>
       <li>item1</li>
       <li>item2</li>
       <li>item3</li>
       <li>item4</li>
       <li>item5</li>
       <li>item6</li>
       <li>item7</li>
       <li>item8</li>
       <li>item9</li>
       <li>item10</li>
    </ul>
</div>

comment dire "scroller le contenu de #container de telle façon que <item3> soit en haut ?
Merci de votre aide
Modifié par PapyJP (15 Sep 2017 - 17:57)
Bonjour PapyJP

Je ne suis pas un crack en Jquery mais voici ma solution.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<div id="container" style="overflow:auto;height:5em;">
    <ul>
       <li>item1</li>
       <li>item2</li>
       <li id="item3">item3</li>
       <li>item4</li>
       <li>item5</li>
       <li>item6</li>
       <li>item7</li>
       <li>item8</li>
       <li>item9</li>
       <li>item10</li>
</div>


<script>
$(document).ready(function() {
$('#container').animate({
        scrollTop: $("#item3").position().top},1000);
});

</script>
Merci de ta réponse
Je parle de Javascript, pas de jQuery
jQuery est un module écrit en Javascript, donc tout ce qui peut se faire en jQuery peut se faire en Javascript
Je n'ai aucune envie d'ajouter un module extérieur à mon site, avec un langage de plus à apprendre, des mises à jours, etc, pour des actions qui sont relativement secondaires par rapport à l'application administrative que je suis en train d'écrire.

Je peux assurer que "item3" est visible en utilisant item3.scrollIntoView(true), mais si item1 est en tête, item3 est déjà visible, donc il ne se passe rien, et ce n'est pas ce que je veux.
Il y a bien sûr un contournement en calculant quel est l'item qui doit être en bas et en demandant qu'il devienne visible, mais il y a certainement un moyen plus direct que je ne parviens pas à trouver.

Toutes les informations que je trouve sur internet concernant scrollBy, scrollTo, etc se réfèrent à déplacer la page dans la fenêtre du navigateur, pas à déplacer un élément dans une <div> scrollable.
Modérateur
Salut,

En Js on doit pouvoir faire un truc du genre (j'ai pas regardé en détail ni testé) :
function scrollDiv(){
    document.getElementById("d").scrollTop += 100;
}

https://stackoverflow.com/questions/29012355/javascript-scrollby-function-executed-on-a-div

Sinon si tu rajoute un id sur l'item et que tu rajoute #item3 à la fin de l'url ca fait quoi ?
J'ai testé avec un <a href="#item3"> ca à l'air de bien se passer mais je ne peux pas tester direct dans l'url avec le fiddle : https://jsfiddle.net/8kf6dbas/
Désolé, je ne comprends pas le concept de "scrollTop" c'est le top de quoi par rapport à quoi?
J'ai fait une page de test dans https://tests.osirisnet.net/migration/tests/scroll.html
Voici le code

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="utf-8" />
    <title>test scroll</title>
    <style type="text/css">
      #container {width:60%;margin:auto;border:1px soli gray;}
      #list {height:5em;margin:10em; border:1px solid blue;overflow:auto;}
    </style>
    <script type="text/javascript">
      function item3toTop() {
        var item3 = document.getElementById('item3');
        item3.scrollTop = 0;
      }
    </script>
  </head>
    <body>
        <div id="container">
      <div id="list" style="overflow:auto;height:5em;">
        <ul>
           <li id="item1">item1</li>
           <li id="item2">item2</li>
           <li id="item3">item3</li>
           <li id="item4">item4</li>
           <li id="item5">item5</li>
           <li id="item6">item6</li>
           <li id="item7">item7</li>
           <li id="item8">item8</li>
           <li id="item9">item9</li>
           <li id="item10">item10</li>
         </ul>
      </div>
      <button onclick="item3toTop()">Item3 en tête</button>
    </div>
    </body>
</html>

Quand je mets un point d'arrêt sur le déroulement du script, je constate que item3.scrollTop vaut déjà 0 avant que je le force... à 0 avec, comme il se doit, aucun résultat visible!
Bonjour
Après une nuit de réflexion, j'ai essayé à nouveau item3.scrollIntoView(true) qui met effectivement item3 en tête, je suppose que j'avais dû faire une erreur dans le code initial.

J'ai donc une solution, mais elle ne permet que de mettre un élément en haut ou en bas de la <div>

J'aimerais clarifier le fonctionnement des scrolls, je ne trouve toujours pas de document clair sur le sujet.
J'ai du mal à croire que cela n'existe pas , ou que ce ne soit pas possible, car il s'agit d'une fonctionnalité banale, à mon sens.
Je pense avoir plus ou moins compris comment ça marche. Cette explication me semble personnellement déroutante, mais peu importe si j'ai effectivement une réponse:
L'objet sur lequel appliquer scrollTop += delta, c'est le conteneur de la liste, c'est à dire #list dans mon exemple, et non #item3 ou le <ul> qui le contient.
C'est à dire que #list.scrollTop représente de la position du contenu de #list par rapport à la position verticale de #list.

Pouvez vous confirmer que j'ai bien compris?

Merci de votre aide.
Modérateur
ScrollIntoView permet effectivement de scroller directement sur un élément. ScrollTop exprime quant à lui le scroll en pixels. Si tu as une div (avec overflow: auto) d'une hauteur de 100 pixels et que son contenu fasse 300 pixels de haut: Tout en haut tu seras à scrollTop == 0 et tout en bas scrollTop == 200. Si tu définis un scrollTop supérieur à 200 cela aura le même effet.

La variance totale de scrolltop est donc la hauteur du contenu moins la hauteur du conteneur. On pourrait donc dire que cela correspond à la hauteur de la partie cachée.

Donc oui tu as bien compris, scrollTop s'applique sur l'élément qui reçoit l'ascenseur, le conteneur. Et contient la position de cet ascenseur.

Tandis que scrollIntoView s'applique sur un élément indépendamment de tout scroll, car il va déplacer le ou les scrolls pour afficher cet élément. «Les» car plusieurs éléments imbriqués ayant un scroll peuvent potentiellement être impliqués.
Oui, c'est ce que j'ai fini par comprendre mais j'ai encore des problèmes de mise en pratique dans le cadre de mon appli administrative, que je ne peux malheureusement pas déplacer dans une zone publique du site.

Ce sur quoi je bute actuellement:
1 - j'ai une <div> qui contient une liste sous forme de <table> plus grande que la <div>
2 - je note la valeur courante de scrollTop
3 - je vide la <div> et remplace son contenu par une autre <table>
4 - je mets le scrollTop de la <div> à l'ancienne valeur

Même en faisant ça pas à pas pour vérifier le fonctionnement, ça ne marche pas.

Première question: la <div> étant la même (c'est la <table> qui change), pourquoi la valeur de scrollTop est elle remise à zéro quand j'en change le contenu?
Deuxième question: pourquoi ne puis-je pas forcer cette valeur à la valeur précédente?

Je soupçonne que ce qu'il y a derrière tout ça c'est que quand on change le contenu d'une <div>, ça prend un certain temps avant que le nouveau contenu soit affiché, et que mon affectation de scrollTop se produit trop tôt.

Votre avis SVP!
Après tests, c'est bien un problème de délai d'affichage.
J'ai dû mettre un timeout de 500ms pour assurer que le contenu de la liste était bine généré, 100ms ne suffisant pas en général.
Y a-t-il un moyen d'avoir un évènement sur un élément pour savoir si son contenu a été complètement affiché?
PapyJP a écrit :
Y a-t-il un moyen d'avoir un évènement sur un élément pour savoir si son contenu a été complètement affiché?

Il semble que cela se fasse avec MutationObserver
La documentation, comme souvent, est faite pour les gens qui savent, pas pour ceux qui découvrent les choses.
Auriez vous un peu d'expérience à partager sur ce sujet?