10 votes

Empêcher la div de défiler vers le haut lorsqu'elle est heurtée par la div située en dessous ?

J'ai demandé une question similaire hier mais je l'ai mal expliqué et je n'ai pas précisé mon souhait d'une solution purement CSS, ce qui devrait être possible, je pense, donc je réessaie.

En gros, j'ai un problème où j'ai un div de messages défilants et un champ de saisie en dessous. Lorsque je clique sur un bouton, j'aimerais que le champ de saisie soit remonté de 100 pixels, sans que la division de messages ne défile également.

Voici un violon qui démontre le problème dans son intégralité

Comme vous pouvez le voir, lorsque vous cliquez sur le bouton "Ajouter une marge", la section des messages défile également vers le haut. Je voudrais qu'elle reste là où elle était. De même, si vous faites légèrement défiler la page vers le haut de sorte que vous ne pouvez voir que l'avant-dernier message, le fait de cliquer sur le bouton devrait également permettre de conserver cette position.

Ce qui est intéressant, c'est que ce comportement est "parfois" préservé. Par exemple, dans certaines circonstances (que je ne peux pas vraiment déduire), la position du défilement est conservée. J'aimerais simplement qu'il se comporte ainsi de manière cohérente.

window.onload = function(e) {
  document.querySelector(".messages").scrollTop = 10000;
};

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin");
}

.container {
     width: 400px;
     height: 300px;
     border: 1px solid #333;
     display: flex;
     flex-direction: column;
}
 .messages {
     overflow-y: auto;
     height: 100%;
}
 .send-message {
     width: 100%;
     display: flex;
     flex-direction: column;
}
 .some-margin {
     margin-bottom: 100px;
}

<div class="container">
   <div class="messages">
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
      <div class="message">hello</div>
   </div>
   <div class="send-message">
      <input />
   </div>
</div>
<button onclick="test()">add margin</button>

enter image description here

0voto

Eliezer Berlin Points 126

Je veux dire, ce qui suit est une solution uniquement CSS qui résout exactement votre exemple :

.some-margin{margin-bottom:100px;}

.messages{margin-top:-100px;}

mais je ne pense pas que ça vous aidera avec votre problème initial du clavier virtuel. Mais peut-être que cela peut inspirer quelqu'un d'autre à trouver une solution.

Le principal problème semble être que la barre de défilement est déjà en faisant exactement ce que vous voulez :

Maintenir sa position afin que le contenu le plus récemment lu soit visible.

Sauf que la barre de défilement a décidé que vous vouliez voir le HAUT du contenu actuellement visible, et non le bas (c'est plus facile à voir si vous utilisez des chiffres) : https://jsfiddle.net/1co3x48n/ )

Si vous êtes prêt à utiliser le javascript, il y a toutes sortes de réponses : https://www.google.com/search?q=scrollbar+always+on+bottom+css+site:stackoverflow.com

Honnêtement, le fait que vous puissiez parcourir plus de 3 pages sur ce sujet et que vous ne trouviez que des réponses en Javascript m'indique que vous ne trouverez pas de réponse uniquement en CSS, et certainement pas une réponse largement compatible avec les navigateurs.

0voto

Ryan Peschel Points 2031

Aucune des solutions proposées ne semble vraiment fonctionner, malheureusement. Le problème de l'utilisation de onFocus pour une zone de texte est qu'elle ne s'applique pas si la zone de texte a déjà le focus. La solution la plus proche que j'ai trouvée jusqu'à présent est la suivante :

componentDidMount() {
  this.screenHeight = window.innerHeight;

  let chatElem = document.querySelector(".conversations-chat");

  window.addEventListener('resize', () => {
    let diff = this.screenHeight - window.innerHeight;

    chatElem.scrollTop += diff;

    this.screenHeight = window.innerHeight;      
  });
}

Cependant, cela ne semble fonctionner que parfois. Cela fonctionne à 100% lorsque l'on clique sur la zone de texte, mais pour une raison quelconque, lorsque l'on ferme le clavier virtuel, cela ne fonctionne que si l'on a fait défiler le texte suffisamment haut. Sinon, elle revient toujours à la même position (près du bas, mais pas tout à fait en bas).

Je ne suis pas sûr de ce qui cause ça. Je vais devoir enquêter davantage demain, je suppose. C'est le plus proche jusqu'à présent.

0voto

Rmaxx Points 861

Créez un conteneur comme dans les exemples ci-dessus, mais modifiez simplement le CSS lorsque vous commencez à taper.

Je ne règle pas la position de la barre de défilement, je déplace simplement l'ensemble du conteneur du message vers le haut. Ainsi, quelle que soit votre position de défilement, elle restera la même. Au moins vers le bas, bien sûr vous ne serez pas en mesure de voir les lignes en haut.

Vous devriez être en mesure d'adapter le css à vos besoins. Vous pourriez même vous passer de JS si vous utilisez :focus ou une configuration CSS légèrement différente, soyez créatif :)

function activate(){
    document.querySelector("#container").classList.toggle("active");
  }

#container{
    position:relative;
    width:300px;
    height:100vh;
    max-height:230px;
    overflow:hidden;
  }
  #messages{
    position:absolute;
    bottom:30px;
    overflow:auto;
    height:200px;
    width:100%;
    background:#eee;
  }
  #container.active #messages {
    bottom:100px;
  }
  #send-message{
    position:absolute;
    border:1px solid #ccc;
    bottom:0;
    height:28px;
  }
  #container.active #send-message{
    height:100px;
  }

<div id="container">
  <div id="messages">
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  <div class="message">hello</div>
  </div>
  <div id="send-message">
    <input id="newmessage" onclick="activate()" type="text" />
  </div>
</div>

0voto

MBadrian Points 400

Vous devez ajouter document.querySelector(".messages").scrollTop = 10000; a test fonction quand ajouter marge alors scrollTop aller à la fin dans la charge que vous mettez scrolltop et lorsque vous ajoutez ou supprimez une marge scrolltop ne s'est pas remis en place Changez votre script comme ceci.

<script>
    window.onload = function(e){ 
    document.querySelector(".messages").scrollTop = 10000;
}

function test() {
    document.querySelector(".send-message").classList.toggle("some-margin")
            document.querySelector(".messages").scrollTop = 10000;
}
    </script>

-1voto

Richard Points 1646

Une approche CSS purement imparfaite que je peux proposer est la suivante :

window.onload = function(e){ 
  document.querySelector(".messages").scrollTop = 10000;
}

document.querySelector('button').addEventListener('click', test)

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin")
  document.querySelector('.wrapper').classList.toggle('wrapper--transformed')
}

.container {
  width: 400px;
  height: 300px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  position: relative;
  overflow-y: auto;
  height: 100%;
}

.wrapper {
  display: block;
}

.wrapper--transformed {
  transform: translateY(-100px);
  margin-bottom: -100px;
}

.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 100px;
}

<div class="container">
  <div class="messages">
    <div class = "wrapper">
      <div class="message">hello1</div>
      <div class="message">hello2</div>
      <div class="message">hello3</div>
      <div class="message">hello4</div>
      <div class="message">hello5</div>
      <div class="message">hello6</div>
      <div class="message">hello7</div>
      <div class="message">hello8</div>
      <div class="message">hello9</div>
      <div class="message">hello1</div>
      <div class="message">hello2</div>
      <div class="message">hello3</div>
      <div class="message">hello4</div>
      <div class="message">hello5</div>
      <div class="message">hello6</div>
      <div class="message">hello7</div>
      <div class="message">hello8</div>
      <div class="message">hello9</div>
      <div class="message">hello1</div>
      <div class="message">hello2</div>
    </div>
  </div>
  <div class="send-message">
    <input />
  </div>
</div>
<button>add margin</button>

La section la plus haute a un petit problème quand la marge est là. L'astuce consiste à utiliser une marge négative et à utiliser la fonction translate pour faire défiler vers le haut (ce n'est pas vraiment un défilement, juste une illusion) l'élément wrapper div.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X