防止div跌破div时向上滚动?


10

昨天我问了一个类似的问题,但解释得很差,并且没有说明我对纯CSS解决方案的渴望,我认为这应该是可能的,因此我正在尝试。

基本上,我遇到了一个问题,即我有一个可滚动消息div,并且在其下方有一个输入字段。当我单击一个按钮时,我希望输入字段增加100像素,而消息区域也不滚动。

这是一个小提琴,充分展示了问题所在

如您所见,当您单击“添加边距”按钮时,消息div也将向上滚动。我希望它能保持原样。同样,如果您稍微向上滚动,因此只能看到倒数第二条消息,则单击按钮时应类似地保持该位置。

有趣的是,这种行为“有时”得以保留。例如,在某些情况下(我无法完全推断),滚动位置得以保留。我只希望它始终如一。

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>

在此处输入图片说明


1
再次您好,我是使用JS回答您问题的人。我想通知您有关您可能误解的事情。您提到:消息div也向上滚动。实际上,不是div向上滚动,而是div的高度在减小。那么为什么这很重要呢?好吧,这意味着scrollbar不会调整其位置。滚动条仅从容器顶部记住其相对位置。当div的高度减小时,滚动条似乎在向上滚动,但实际上并非如此。
理查德

1
您的帖子非常合理(从某种意义上说,人们知道您想要什么结果),但是我只是在分享一些信息,以防您对知识不了解(以防它可能帮助您提出解决方案)说问题);-)
理查德

是的,非常正确,感谢您的澄清。它只是像向上滚动一样“看起来”,因为您看不到曾经可以看到的较低内容。实际上,滚动位置并没有改变。有点幻觉。是的,这可能有助于提出解决方案。
Ryan Peschel

Answers:


5

您可能会喜欢这个有趣的解决方案。

我们对div的了解是,它仅保留滚动条的顶部位置,因此,如果由于任何原因使高度发生变化,滚动条将保持不变,这就是导致您出现问题的原因。

解决方法是,您可以使用翻转.messages180度transform: rotate(180deg) scaleX(-1);并向后翻转.message来取消翻转内容,然后div将自动保持底部的滚动条(顶部)。

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>


这有一个问题,即向后滚动鼠标滚轮(向上滚动向下,向下滚动向上)
Ryan Peschel

好的,我花了很多时间,但是现在其他开发人员还有3个您不想要的答案:)我希望可以帮助您,祝您好运。但是作为建议支持者,如果他们花时间尝试回答您的问题,则不会因此而收费。
罗勒

2
当然可以 无论如何
Ryan Peschel

这非常聪明;-)不幸的是,反向滚动有点令人讨厌。
理查德

3

滚动条的正常行为是在顶部,因此,当您将其设置为页面加载的底部时,则必须自己维护,因为一旦按下下面的内容,则div滚动将移至顶部。

因此,我为您提供两种解决方案:

  1. 反转消息div中的消息,使最后一条消息为第一条,因此滚动始终位于顶部。

  2. 我创建了一个javascript函数,以滚动到任何元素的底部,因此只要您想滚动到底部,就可以调用它。

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

检查代码段

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>


不幸的是,我不想滚动到仅滚动到底部。我想保持其立场。另外,很可能无需Java语言即可完成此操作。在OP中:“类似地,如果您稍微向上滚动,因此只能看到倒数第二条消息,则单击按钮应类似地在单击时保持该位置。”
Ryan Peschel

3

您可以用另一种方法来实现它,方法是将高度赋予.messages 而不是赋予高度,.container在这种情况下,它不会影响消息,div但是如果给予高度,.container则会推动div,因为页边距位于主体内部div有一个高度。

检查此片段

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>


这行不通,因为需要将边距应用于.send-message。如果您看一下我之前的问题,那么这样做是因为它类似于在移动设备上打开虚拟键盘所带来的利润上升(利润率底部只是用于调试解决方案的1:1替代品)
Ryan Peschel

3

一种简单的解决方法是设置前一个scrollTop开关。在这里,我使用数据集来存储先前的scrollTop值,也可以使用变量。

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

我的意思是,以下是仅CSS的解决方案,可以完全解决您的示例:

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

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

但我认为这不会帮助您解决虚拟键盘的原始问题。但这可能会激发其他人寻求解决方案。

主要问题似乎是滚动条已经完全在执行您想要的操作:

保持其位置,以便可以看到最新阅读的内容。

除了滚动条之外,您还想查看当前可见内容的顶部,而不是底部。(更容易查看是否使用数字:https : //jsfiddle.net/1co3x48n/

如果您愿意使用javascript,则有各种答案:https : //www.google.com/search?q= scrollbar+always+on+bottom+css+site: stackoverflow.com

老实说,您可以浏览〜3 +页以上的页面并仅找到Javascript答案这一事实告诉我,您将不会找到仅CSS的答案,当然也不是与浏览器广泛兼容的答案。


0

所提供的解决方案似乎都没有真正不幸地起作用。使用onFocus文本框的问题在于,如果文本框已经具有焦点,则该文本框将不适用。我已经弄了几个小时了,到目前为止,我想出的最接近的解决方案是:

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

但是,这似乎有时才起作用。单击文本框时,它可以100%地起作用,但是由于某种原因,当关闭虚拟键盘时,它只有在向上滚动时才起作用。否则,每次都会重置到相同位置(靠近底部,但不完全是底部)。

不知道是什么原因造成的。我想明天将不得不进行更多调查。到目前为止,这是最接近的。


就像我们所有人在回答中所说的那样,仅靠CSS似乎是不可能的。(您的JS代码有一个问题,就是chatElem.scrollTop不能小于0,因此,如果它太靠近顶部,它将尝试变为负数,而变为0,然后将屏幕放大再次,出现了以前没有的滚动。)
Eliezer Berlin

同样,chatElem.scrollTop不能超过chatElem.scrollHeight-chatElem.offsetHeight,因此,如果尝试这样做,它将创建一个以前没有滚动的额外滚动。
柏林Eliezer

0

像上面的示例一样创建一个容器,但是当您开始输入时只需更改CSS。

我没有设置滚动条的位置,只是向上移动整个消息容器。因此,无论您的滚动位置如何,都将保持不变。至少向下,您当然看不到顶部的线条。

您应该能够根据需要调整CSS。如果使用:focus或稍微不同的CSS设置,甚至可以不使用JS,请发挥创造力:)

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

您必须在添加边距时添加document.querySelector(".messages").scrollTop = 10000;test函数中,然后scrollTop在设置的负载中结束,scrolltop并且在添加边距或移除边距scrolltop未设置时再次更改脚本,使其像这样

<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

js切换功能似乎存在问题。我已将其更改为简单的隐藏与显示。另外,我还在输入标签上添加了宽度。您还需要在send-message div上添加一个位置:absolute,并在底部设置一个bottom:0,使其停留在底部。然后将position:relative放置在容器上,以便发送消息div停留在容器内。这意味着消息容器不会影响消息本身,也不会增加消息。

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>


我不明白这个解决方案。单击添加边距时,似乎只是隐藏了发送消息文本框?
Ryan Peschel

-1

我可以提出的一种不完美的CSS方法如下:

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>

当有边距时,最上面的部分有一个小问题。这里的技巧是使用负边距,并使用转换将wrapperdiv “向上滚动”(不是真正的滚动,只是一种幻觉)。


是的,最顶层的问题有点问题。另外,这是否假定知道移动键盘的确切大小并知道要补偿多少?我不确定是否可以访问该信息。
Ryan Peschel

要回答您的问题:是的。上述技术必须知道键盘的确切高度。但是,有些方法可以使用JS来确定元素的高度并更改CSS。
理查德

您如何确定移动虚拟键盘的高度?
Ryan Peschel

@RyanPeschel该虚拟键盘是HTML的元素(例如div)吗?
理查德

我不确定它的编码方式。
Ryan Peschel

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.