Verhindern Sie, dass Div nach oben rollt, wenn Sie von Div darunter gestoßen werden?


10

Ich habe gestern eine ähnliche Frage gestellt , sie aber schlecht erklärt und meinen Wunsch nach einer reinen CSS-Lösung, die meiner Meinung nach möglich sein sollte, nicht spezifiziert, also versuche ich es erneut.

Grundsätzlich habe ich ein Problem, bei dem ein Teil der scrollbaren Nachrichten und ein Eingabefeld darunter angezeigt werden. Wenn ich auf eine Schaltfläche klicke, möchte ich, dass das Eingabefeld um 100 Pixel vergrößert wird, ohne dass auch das Div der Nachrichten gescrollt wird.

Hier ist eine Geige, die das Problem in seiner Gesamtheit demonstriert

Wie Sie sehen können, wird beim Klicken auf die Schaltfläche "Rand hinzufügen" auch die Meldung div nach oben gescrollt. Ich möchte, dass es dort bleibt, wo es war. Wenn Sie leicht nach oben gescrollt sind, sodass Sie nur die vorletzte Nachricht sehen können, sollte das Klicken auf die Schaltfläche diese Position beim Klicken ebenfalls beibehalten.

Das Interessante ist, dass dieses Verhalten "manchmal" erhalten bleibt. Zum Beispiel wird unter bestimmten Umständen (die ich nicht ganz ableiten kann) die Bildlaufposition beibehalten. Ich möchte nur, dass es sich konsequent als solches verhält.

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>

Geben Sie hier die Bildbeschreibung ein


1
Hallo nochmal, ich bin derjenige, der Ihre Frage mit JS beantwortet hat. Ich möchte Sie über etwas informieren, das Sie möglicherweise falsch interpretiert haben. Sie haben erwähnt: Die Nachrichten div scrollt ebenfalls nach oben . Eigentlich ist es nicht das div, was nach oben rollt, sondern die Höhe des Div, die abnimmt. Warum ist das so wichtig? Nun, was es bedeutet ist, dass der scrollbarseine Position nicht anpasst. Die Bildlaufleiste merkt sich nur die Position relativ zum oberen Rand des Containers. Wenn die Höhe des Divs abnimmt, scheint die Bildlaufleiste nach oben zu scrollen, ist es aber nicht.
Richard

1
Ihr Beitrag ist absolut sinnvoll (in dem Sinne, dass die Leute wissen, welches Ergebnis Sie wollen), aber ich teile nur etwas, falls Ihnen das Wissen nicht klar ist (falls es Ihnen helfen kann, eine Idee zur Lösung zu finden besagtes Problem) ;-)
Richard

Ja sehr wahr, danke für die Klarstellung. Es "sieht" nur so aus, als würde es nach oben scrollen, weil Sie den niedrigeren Inhalt nicht sehen können, den Sie einmal konnten. In Wirklichkeit ändert sich die Bildlaufposition nicht. Ein bisschen wie eine Illusion. Ja, das könnte helfen, eine Lösung zu finden.
Ryan Peschel

Antworten:


5

Dies ist eine lustige Lösung, die Ihnen gefallen könnte.

Was wir über das div wissen, ist, dass es nur die oberste Position der Bildlaufleiste beibehält. Wenn sich also die Höhe aus irgendeinem Grund ändert, bleibt die Bildlaufleiste gleich und dies ist der Grund für Ihr Problem.

Um dieses Problem zu umgehen, können Sie den .messages180-Grad- transform: rotate(180deg) scaleX(-1);Wert mit und umdrehen .message, um das Umdrehen des Inhalts abzubrechen. Das Div behält dann automatisch die untere Bildlaufleiste (die oben ist) bei.

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%;
  transform: rotate(180deg) scaleX(-1);
}

.message
{
  transform: rotate(180deg) scaleX(-1);
}
.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 100px;
}
<div class="container">
  <div class="messages">
  <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">hello10</div>
  <div class="message">hello11</div>
  <div class="message">hello12</div>
  <div class="message">hello13</div>
  <div class="message">hello14</div>
  <div class="message">hello15</div>
  <div class="message">hello16</div>
  <div class="message">hello17</div>
  <div class="message">hello18</div>
  <div class="message">hello19</div>
  <div class="message">hello20</div>
  </div>
  <div class="send-message">
  <input />
  </div>
</div>

<button onclick="test()">add margin</button>


Dies hat das Problem, dass das Scrollen des Mausrads rückwärts erfolgt (das Scrollen nach oben geht nach unten und das Scrollen nach unten geht nach oben)
Ryan Peschel

Ok, ich habe viel Zeit damit verbracht, aber jetzt haben andere Entwickler 3 Antworten, nach denen Sie nicht suchen :) Ich hatte gehofft, Ihnen zu helfen und Ihnen viel Glück zu wünschen. Aber als Ratschlag, der Zeit damit verbringt, Ihre Frage zu beantworten, werden Sie dadurch nicht belastet.
Basil

2
Sichere Sache. Trotzdem danke
Ryan Peschel

Das ist sehr clever ;-) Leider ist das umgekehrte Scrollen etwas abstoßend.
Richard

3

Das normale Verhalten der Bildlaufleiste ist, dass sie sich oben befindet. Wenn Sie sie also beim Laden der Seite auf den unteren Rand setzen, müssen Sie sie selbst beibehalten, da Div Scroll immer dann nach oben verschoben wird, wenn der unten stehende Inhalt sie verschoben hat.

Ich habe also zwei Lösungen für Sie:

  1. Kehren Sie die Nachrichten innerhalb des Nachrichtendivs um, sodass die letzte Nachricht die erste ist und der Bildlauf immer oben ist.

  2. Ich habe eine Javascript-Funktion erstellt, um zum Ende eines Elements zu scrollen, sodass Sie es immer dann aufrufen, wenn Sie zum Ende scrollen möchten.

function scrollbottom(e)
    {
      e.scrollTop = e.clientHeight;
    }

Überprüfen Sie das Snippet

var elem = document.querySelector(".messages");

window.onload = function(e){ 
  scrollbottom(elem);
}

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

function scrollbottom(e)
{
  e.scrollTop = e.clientHeight;
}
.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>


Leider möchte ich nicht scrollen, um nur nach unten zu scrollen. Ich möchte seine Position behaupten. Es ist auch wahrscheinlich, dass dies ohne Javascript möglich ist. Aus dem OP: "Wenn Sie leicht nach oben gescrollt sind, sodass Sie nur die vorletzte Nachricht sehen können, sollte das Klicken auf die Schaltfläche diese Position beim Klicken ebenfalls beibehalten."
Ryan Peschel

3

Sie können es umgekehrt machen, indem Sie die Höhe dem geben, .messages anstatt es dem zu geben. .containerIn diesem Fall hat dies keine Auswirkungen auf die Nachrichten. divWenn Sie es dem geben, .containerwird Ihr Div verschoben, da sich der Rand innerhalb des Hauptbereichs befindet div die eine Höhe haben.

Überprüfen Sie dieses Snippet

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin");
}
.container {
  width: 400px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  height: 300px;
  overflow-y: auto;
}

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

.some-margin {
  margin-bottom: 50px;
}
<div class="container">
  <div class="messages">
  <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">hello10</div>
  <div class="message">hello11</div>
  <div class="message">hello12</div>
  <div class="message">hello13</div>
  <div class="message">hello14</div>
  <div class="message">hello15</div>
  <div class="message">hello16</div>
  <div class="message">hello17</div>
  <div class="message">hello18</div>
  <div class="message">hello19</div>
  <div class="message">hello20</div>
  </div>
  <div class="send-message">
  <input />
  </div>
</div>

<button onclick="test()">add margin</button>


Dies funktioniert nicht, da der Rand angewendet werden muss .send-message. Wenn Sie sich meine vorherige Frage ansehen, geschieht dies, weil es dem Randstoß beim Öffnen der virtuellen Tastatur auf Mobilgeräten ähnelt (der Rand unten ist nur ein 1: 1-Ersatz zum Debuggen der Lösung)
Ryan Peschel

3

Die einfache Problemumgehung besteht darin, den vorherigen scrollTopSchalter umzuschalten. Hier verwende ich einen Datensatz , um den vorherigen scrollTopWert zu speichern . Sie können auch eine Variable verwenden.

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

function test() {
  let state = document.querySelector(".send-message").classList.toggle("some-margin")
  let div = document.querySelector(".messages");

  if (state) {
    div.dataset.top = div.scrollTop;
    div.scrollTop += 100 // same as margin-bottom of .some-margin
  } else {
    div.scrollTop = div.dataset.top;
  }
}
.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">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">hello10</div>
    <div class="message">hello11</div>
    <div class="message">hello12</div>
    <div class="message">hello13</div>
    <div class="message">hello14</div>
    <div class="message">hello15</div>
    <div class="message">hello16</div>
    <div class="message">hello17</div>
    <div class="message">hello18</div>
    <div class="message">hello19</div>
    <div class="message">hello20</div>
  </div>
  <div class="send-message">
    <input />
  </div>
</div>

<button onclick="test()">add margin</button>


0

Ich meine, das Folgende ist eine reine CSS-Lösung, die genau Ihr Beispiel löst:

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

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

aber ich denke nicht, dass es Ihnen bei Ihrem ursprünglichen Problem der virtuellen Tastatur helfen wird. Aber vielleicht kann dies jemand anderen zu einer Lösung inspirieren.

Das Hauptproblem scheint zu sein, dass die Bildlaufleiste bereits vorhanden ist genau das tut, was Sie wollen:

Behalten Sie die Position bei, damit der zuletzt gelesene Inhalt sichtbar ist.

Außer die Bildlaufleiste entscheidet, dass Sie die Oberseite des aktuell sichtbaren Inhalts sehen möchten, nicht die Unterseite. (Es ist einfacher zu erkennen, ob Sie Zahlen verwenden: https://jsfiddle.net/1co3x48n/ )

Wenn Sie bereit sind, Javascript zu verwenden, gibt es alle möglichen Antworten: https://www.google.com/search?q=scrollbar+always+on+bottom+css+site:stackoverflow.com

Ehrlich gesagt, die Tatsache, dass Sie ~ 3 + Seiten davon durchgehen und nur Javascript-Antworten finden können, sagt mir, dass Sie keine Nur-CSS-Antwort finden werden, schon gar keine, die weitgehend browserkompatibel ist.


0

Keine der angebotenen Lösungen scheint leider wirklich zu funktionieren. Das Problem bei der Verwendung onFocusfür ein Textfeld besteht darin, dass es nicht angewendet wird, wenn das Textfeld bereits den Fokus hat. Ich habe stundenlang damit herumgespielt und die nächste Lösung, die ich bisher gefunden habe, ist folgende:

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;      
  });
}

Dies scheint jedoch nur manchmal zu funktionieren. Es funktioniert 100% der Zeit, wenn Sie auf das Textfeld klicken, aber aus irgendeinem Grund funktioniert es beim Schließen der virtuellen Tastatur nur, wenn es ausreichend nach oben gescrollt wurde. Andernfalls wird es jedes Mal auf dieselbe Position zurückgesetzt (in der Nähe des Bodens, aber nicht ganz unten).

Ich bin mir nicht sicher, was das verursacht. Ich nehme an, ich muss morgen mehr Nachforschungen anstellen. Dies ist jedoch die bisher nächstgelegene.


Wie wir alle in unseren Antworten gesagt haben, scheint es unmöglich, nur mit CSS allein zu arbeiten. (Es gibt ein Problem mit Ihrem JS-Code, nämlich, dass chatElem.scrollTop nicht kleiner als 0 sein darf. Wenn es also zu nahe am oberen Rand liegt , wird versucht, eine negative Zahl zu werden. Stattdessen wird es 0, wenn Sie den Bildschirm vergrößern wieder erscheint eine Schriftrolle, wo es vorher keine gab.)
Eliezer Berlin

Aus dem gleichen Grund kann chatElem.scrollTop nicht mehr als chatElem.scrollHeight - chatElem.offsetHeight sein. Wenn Sie dies versuchen, wird eine zusätzliche Schriftrolle erstellt, in der zuvor keine vorhanden war.
Eliezer Berlin

0

Erstellen Sie einen Container wie in den obigen Beispielen, ändern Sie jedoch einfach das CSS, wenn Sie mit der Eingabe beginnen.

Ich stelle die Position der Bildlaufleiste nicht ein, sondern bewege den gesamten Nachrichtencontainer nach oben. Was auch immer Ihre Bildlaufposition sein mag, sie bleibt gleich. Zumindest nach unten können Sie die Linien oben natürlich nicht sehen.

Sie sollten in der Lage sein, das CSS an Ihre Bedürfnisse anzupassen. Sie könnten sogar auf JS verzichten, wenn Sie Folgendes verwenden: Fokus oder etwas anderes CSS-Setup, seien Sie kreativ :)

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>


0

Sie müssen hinzufügen document.querySelector(".messages").scrollTop = 10000;zutest Funktion hinzufügen, wenn Sie einen Rand hinzufügen scrollTop, scrolltopund dann zum Ende der von Ihnen festgelegten Last gehen. Wenn Sie einen Rand hinzufügen oder einen Rand entfernen scrolltop, wurde das Skript nicht so geändert, dass es Ihnen gefällt

<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>

0

Es scheint ein Problem mit der Umschaltfunktion von js zu geben. Ich habe es in ein einfaches Verstecken geändert. Außerdem habe ich dem Eingabe-Tag eine Breite hinzugefügt. Sie müssen auch eine Position hinzufügen: absolut in der Send-Nachricht div und unten: 0, damit sie unten bleibt. Platzieren Sie dann position: relative auf dem Container, sodass die send message div im Container bleibt. Dies bedeutet, dass der Nachrichtencontainer die Nachrichten selbst nicht beeinflusst und sie nach oben drückt.

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

function test() {
  var x = document.querySelector(".send-message");

  if (x.style.display === "none") {
    x.style.display = "block";
  } else {
    x.style.display = "none";
  }
}
.container {
     width: 400px;
     height: 300px;
     border: 1px solid #333;
     display: flex;
     flex-direction: column;
     position: relative;
}
 .messages {
     overflow-y: auto;
     height: 100%;
}
 .send-message {
     width: 100%;
     display: flex;
     flex-direction: column;
     position: absolute;
     bottom: 0;
}
 .send-message input {
     width:100%;
}
 .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">test</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>


Ich verstehe diese Lösung nicht. Es scheint nur das Textfeld "Nachricht senden" auszublenden, wenn Sie auf "Rand hinzufügen" klicken.
Ryan Peschel

-1

Ein reiner unvollkommener CSS-Ansatz, den ich entwickeln kann, ist der folgende:

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>

Der oberste Abschnitt hat ein kleines Problem, wenn der Rand vorhanden ist. Der Trick hier besteht darin, einen negativen Rand zu verwenden und mit translate zu "scrollen" (nicht wirklich eine Schriftrolle, nur eine Illusion) wrapper.


Das oberste Abschnittsthema ist ein kleines Problem, ja. Vorausgesetzt, dies setzt voraus, dass Sie die genaue Größe der mobilen Tastatur kennen, um zu wissen, um wie viel zu kompensieren ist? Ich bin mir nicht sicher, ob ich Zugriff auf diese Informationen habe.
Ryan Peschel

Um Ihre Frage zu beantworten: Ja. Die obige Technik muss die genaue Höhe der Tastatur kennen. Es gibt jedoch Möglichkeiten, mit JS die Höhe eines Elements zu bestimmen und das CSS zu ändern.
Richard

Wie würden Sie die Höhe der mobilen virtuellen Tastatur bestimmen?
Ryan Peschel

@ RyanPeschel Ist diese virtuelle Tastatur ein Element von HTML (z. B. div)?
Richard

Ich bin nicht sicher, wie es codiert ist.
Ryan Peschel

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.