その下のdivにぶつかったときにdivが上にスクロールしないようにしますか?


10

私は昨日、同様の質問をしましたが、説明が不十分であり、純粋なCSSソリューションへの私の希望を明記していませんでした。

基本的に、スクロール可能なメッセージのdivとその下に入力フィールドがあるという問題があります。ボタンをクリックしたときに、メッセージのdivもスクロールせずに、入力フィールドを100ピクセル増やしたいと思います。

ここに問題全体を示すフィドルがあります

ご覧のように、「マージンを追加」ボタンをクリックすると、メッセージのdivも上にスクロールします。そのままにしてもらいたいです。同様に、少し上にスクロールして最後から2番目のメッセージしか表示できない場合、ボタンをクリックしても、クリックしたときにその位置が維持されるはずです。

興味深いのは、この動作が「ときどき」維持されることです。たとえば、状況によっては(かなり推測することはできません)、スクロール位置が保持されます。私はそれが一貫してそのように振る舞うことを望みます。

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
あなたの投稿は(あなたが望む結果を人々が知っているという意味で)完全に理にかなっていますが、知識があなたに明らかでない場合に備えて、私は何かを共有しています(解決するためのアイデアを思い付くのに役立つ場合があります)上記の問題);-)
Richard

わかりました。ありがとうございます。上にスクロールしているように「見える」だけです。以前は見られなかった下位のコンテンツを見ることができないからです。実際には、スクロール位置は変わりません。ちょっとした幻想。ええ、それは解決策を考え出すのに役立つかもしれません。
Ryan Peschel

回答:


5

これはあなたが好むかもしれない面白い解決策です。

divについて私たちが知っていることは、スクロールバーの上部の位置のみを保持するため、何らかの理由で高さが変更された場合、スクロールバーは同じままであり、これが問題の原因です。

回避策としては、反転することができます.messages使用して180度に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

Ok私はこれに多くの時間を費やしましたが、今でも他の開発者はあなたが探していない3つの答えを持っています:)私はあなたが幸運を祈るのを手伝うことを望んでいました。しかし、あなたの質問に答えようとすることに時間を費やすアドバイス賛成票として、あなたはそれをすることによって請求されることはありません。
バジル

2
確実なこと。とにかくありがとう
Ryan Peschel

これはとても賢いです;-)残念ながら、逆スクロールは少し不快です。
リチャード

3

スクロールバーの通常の動作は上部に表示されるため、ページの読み込み時に下部に設定すると、下のコンテンツがプッシュするとdivスクロールが上部に移動するため、それを自分で維持する必要があります。

したがって、私には2つの解決策があります。

  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>


残念ながら、一番下までスクロールしたくありません。その立場を維持したい。また、これはJavascriptなしで実行できる可能性があります。OPから:「同様に、少し上にスクロールして最後から2番目のメッセージしか表示できない場合、ボタンをクリックすると、クリックしてもその位置が維持されるはずです。」
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

簡単な回避策は、前のscrollToponトグルを設定することです。ここでは、データセットを使用して以前の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〜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関数に追加する必要があります。マージンを追加するか、マージンを削除しなかった場合、再度設定しなかったため、スクリプトを次のように変更します。scrollTopscrolltopscrolltop

<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の絶対値と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を変更する方法があります。
Richard

モバイル仮想キーボードの高さをどのように決定しますか?
Ryan Peschel

@RyanPeschelその仮想キーボードはHTMLの要素divですか(例)?
Richard

どのようにコード化されているのかわかりません。
Ryan Peschel

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.