Cegah div bergulir ke atas saat terbentur oleh div di bawahnya?


10

Saya mengajukan pertanyaan serupa kemarin tetapi menjelaskannya dengan buruk, dan tidak menentukan keinginan saya untuk solusi murni-CSS, yang saya pikir seharusnya mungkin, jadi saya coba lagi.

Pada dasarnya, saya memiliki masalah di mana saya memiliki div pesan yang dapat digulir dan bidang input di bawahnya. Ketika saya mengklik sebuah tombol, saya ingin bidang input ditabrak hingga 100 piksel, tanpa harus gulir div pesan juga.

Berikut adalah biola yang menunjukkan masalah secara keseluruhan

Seperti yang Anda lihat, ketika Anda mengklik tombol "tambahkan margin", div pesan juga akan bergulir. Saya ingin tinggal di tempat itu. Demikian pula, jika Anda sedikit digulir ke atas sehingga Anda hanya dapat melihat pesan kedua hingga terakhir, mengklik tombolnya juga harus mempertahankan posisi itu saat diklik.

Yang menarik adalah bahwa perilaku ini "kadang-kadang" dipertahankan. Misalnya, dalam beberapa keadaan (yang saya tidak bisa menyimpulkan) posisi gulir dipertahankan. Saya hanya ingin hal itu berlaku secara konsisten.

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>

masukkan deskripsi gambar di sini


1
Halo lagi, saya yang menjawab pertanyaan Anda menggunakan JS. Saya ingin memberi tahu Anda tentang sesuatu yang mungkin Anda salah artikan. Anda menyebutkan: pesan div juga menggulung ke atas . Sebenarnya, bukan divyang bergulir ke atas, tapi ketinggian div yang menurun. Jadi mengapa ini penting? Nah, apa artinya adalah bahwa scrollbartidak menyesuaikan posisinya. Scrollbar hanya mengingat posisinya relatif dari atas wadahnya. Ketika ketinggian div menurun, sepertinya scrollbar sedang bergulir, tetapi sebenarnya tidak.
Richard

1
Posting Anda masuk akal (dalam arti bahwa orang tahu apa hasil yang Anda inginkan), tapi saya hanya berbagi sesuatu jika pengetahuan tidak jelas bagi Anda (jika itu dapat membantu Anda untuk datang dengan ide untuk menyelesaikan kata masalah) ;-)
Richard

Ya benar sekali, terima kasih atas klarifikasi. Itu hanya "terlihat" seperti sedang bergulir ke atas, karena Anda tidak dapat melihat konten yang lebih rendah yang pernah Anda bisa. Pada kenyataannya posisi gulir tidak berubah. Sedikit ilusi. Ya, itu mungkin membantu menghasilkan solusi.
Ryan Peschel

Jawaban:


5

Ini adalah solusi lucu yang mungkin Anda sukai.

Apa yang kita ketahui tentang div bahwa itu hanya mempertahankan posisi atas bilah gulir jadi jika ketinggian berubah karena alasan apa pun bilah gulir akan tetap sama dan inilah yang menyebabkan masalah Anda.

Sebagai solusi Anda dapat membalik .messages180 derajat menggunakan transform: rotate(180deg) scaleX(-1);dan membalik kembali .messageuntuk membatalkan membalik konten maka div akan mempertahankan scrollbar bawah (yang atas) secara otomatis.

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>


Ini memiliki masalah ketika menggulir roda mouse ke belakang (menggulir ke atas ke bawah dan ke bawah ke atas)
Ryan Peschel

Ok saya menghabiskan banyak waktu untuk hal ini tetapi masih sekarang pengembang lain memiliki 3 jawaban yang tidak Anda cari :) saya berharap dapat membantu Anda mengucapkan semoga sukses. tetapi sebagai saran, suara positif yang menghabiskan waktu mencoba menjawab pertanyaan Anda, Anda tidak akan dikenakan biaya dengan melakukannya.
Basil

2
Tentu saja. Terima kasih lagi
Ryan Peschel

Ini sangat pintar ;-) Sayangnya, pengguliran yang terbalik agak tidak menyenangkan.
Richard

3

Perilaku normal scrollbar itu berada di atas, jadi ketika Anda mengaturnya ke bawah pada halaman memuat, Anda harus mempertahankannya sendiri karena ketika konten di bawah ini mendorongnya maka div scroll akan pindah ke atas.

Jadi saya punya dua solusi untuk Anda:

  1. Balikkan pesan di dalam div pesan sehingga pesan terakhir akan menjadi yang pertama sehingga gulir akan selalu berada di atas.

  2. Saya membuat fungsi javascript untuk menggulir ke bagian bawah elemen apa pun sehingga Anda cukup menyebutnya kapan saja Anda ingin menggulir ke bagian bawah.

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

Periksa cuplikannya

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>


Sayangnya saya tidak ingin gulir untuk hanya gulir ke bawah. Saya ingin mempertahankan posisinya. Juga, kemungkinan hal ini dapat dilakukan tanpa Javascript. Dari OP: "Demikian pula, jika Anda sedikit digulir ke atas sehingga Anda hanya dapat melihat pesan kedua hingga terakhir, mengklik tombolnya juga harus mempertahankan posisi itu saat diklik."
Ryan Peschel

3

Anda dapat melakukannya sebaliknya, dengan memberikan ketinggian ke .messages alih alih memberikannya ke .containerdalam hal ini tidak akan mempengaruhi pesan divtetapi jika Anda memberikannya kepada .containeritu akan mendorong div Anda karena margin berada di dalam main div yang memiliki ketinggian.

Periksa cuplikan ini

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>


Ini tidak berhasil karena margin perlu diterapkan .send-message. Jika Anda melihat pertanyaan saya sebelumnya, ini dilakukan karena mirip dengan margin bump dari membuka keyboard virtual pada perangkat seluler (margin bawah hanyalah pengganti 1: 1 untuk men-debug solusi)
Ryan Peschel

3

Solusi sederhana adalah dengan mengatur sebelumnya scrollToppada sakelar. Di sini saya menggunakan dataset untuk menyimpan scrollTopnilai sebelumnya , Anda juga bisa menggunakan variabel.

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

Maksud saya, berikut ini adalah solusi CSS saja yang memecahkan persis contoh Anda:

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

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

tapi saya pikir itu tidak akan membantu Anda dengan masalah awal Anda dari keyboard virtual. Tapi mungkin ini bisa menginspirasi orang lain untuk solusi.

Masalah utama tampaknya adalah scrollbar sudah melakukan apa yang Anda inginkan:

Mempertahankan posisinya sehingga konten yang paling baru dibaca terlihat.

Kecuali bilah gulir memutuskan bahwa Anda ingin melihat TOP dari konten yang saat ini terlihat, bukan bagian bawah. (Lebih mudah untuk melihat apakah Anda menggunakan angka: https://jsfiddle.net/1co3x48n/ )

Jika Anda bersedia menggunakan javascript, ada segala macam jawaban: https://www.google.com/search?q=scrollbar+always+on+bottom+css+site:stackoverflow.com

Jujur saja, fakta bahwa Anda dapat melewati ~ 3 + halaman ini dan hanya menemukan jawaban Javascript yang memberi tahu saya bahwa Anda tidak akan menemukan jawaban khusus CSS, tentu saja bukan yang kompatibel dengan banyak browser.


0

Sayangnya, tidak ada solusi yang benar-benar berfungsi. Masalah dengan menggunakan onFocusuntuk kotak teks adalah bahwa itu tidak akan berlaku jika kotak teks sudah memiliki fokus. Saya telah bermain-main dengan ini selama berjam-jam dan solusi terdekat saya sampai sejauh ini adalah ini:

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

Namun, ini sepertinya hanya kadang-kadang berhasil. Ini berfungsi 100% dari waktu ketika mengklik kotak teks, tetapi untuk beberapa alasan ketika menutup keyboard virtual itu hanya berfungsi jika digulirkan ke atas. Kalau tidak, itu me-reset ke posisi yang sama setiap kali (dekat bagian bawah, tetapi tidak cukup bagian bawah).

Tidak yakin apa yang menyebabkannya. Saya harus menyelidiki lebih banyak besok. Ini adalah yang terdekat sejauh ini.


Seperti yang kita semua katakan di jawaban kami, sepertinya tidak mungkin dilakukan hanya dengan CSS saja. (Ada masalah dengan kode JS Anda, yaitu bahwa chatElem.scrollTop tidak boleh kurang dari 0 , jadi jika terlalu dekat bagian atas, ia mencoba menjadi angka negatif, menjadi 0 sebagai gantinya, maka ketika Anda membuat layar lebih besar lagi, sebuah gulir muncul di tempat yang sebelumnya tidak ada.)
Eliezer Berlin

Dengan cara yang sama, chatElem.scrollTop tidak boleh lebih dari chatElem.scrollHeight - chatElem.offsetHeight , jadi itu akan membuat gulir tambahan di mana tidak ada sebelumnya jika Anda mencoba melakukan itu.
Eliezer Berlin

0

Buat wadah seperti dalam contoh di atas, tetapi kemudian ubah saja CSS saat Anda mulai mengetik.

Saya tidak mengatur posisi scrollbar, hanya memindahkan seluruh wadah pesan ke atas. Jadi, apa pun posisi gulir Anda mungkin, akan tetap sama. Setidaknya ke bawah, tentu saja Anda tidak akan dapat melihat garis di atas.

Anda harus dapat menyesuaikan css dengan kebutuhan Anda. Anda bahkan dapat pergi tanpa JS jika Anda menggunakan: fokus atau pengaturan CSS yang sedikit berbeda, jadilah kreatif :)

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

Anda harus menambahkan document.querySelector(".messages").scrollTop = 10000;untuk testfungsi ketika add marjin kemudian scrollToppergi untuk mengakhiri beban Anda mengatur scrolltopdan ketika Anda menambahkan margin atau marjin remove scrolltoptidak mengatur lagi mengubah Anda script untuk seperti ini

<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

Tampaknya ada masalah dengan fungsi js toggle. Saya telah mengubahnya menjadi hide & show sederhana. Saya juga telah menambahkan lebar pada tag input. Anda juga perlu menambahkan posisi: absolut pada div kirim-pesan dan bawah: 0 sehingga tetap di bawah. kemudian posisikan posisi: relatif pada wadah sehingga div pesan kirim tetap berada di dalam wadah. Ini berarti bahwa wadah pesan tidak akan memengaruhi pesan itu sendiri dan mendorongnya ke atas.

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>


Saya tidak mengerti solusi ini. Sepertinya menyembunyikan kotak pesan kirim ketika Anda mengklik tambahkan margin?
Ryan Peschel

-1

Pendekatan CSS murni yang tidak sempurna yang bisa saya buat adalah sebagai berikut:

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>

Bagian paling atas memiliki sedikit masalah ketika margin ada di sana. Kuncinya di sini adalah menggunakan margin negatif dan menggunakan translate untuk "scroll up" (bukan benar-benar sebuah scroll, hanya ilusi) wrapperdiv.


Masalah bagian paling atas adalah sedikit masalah, ya. Juga, apakah ini menganggap mengetahui ukuran yang tepat dari keyboard ponsel untuk mengetahui berapa banyak kompensasi? Saya tidak yakin apakah saya memiliki akses ke informasi itu.
Ryan Peschel

Untuk menjawab pertanyaan Anda: ya. Teknik di atas harus mengetahui ketinggian keyboard yang tepat. Namun, ada beberapa cara menggunakan JS untuk menentukan ketinggian elemen dan mengubah CSS.
Richard

Bagaimana Anda menentukan ketinggian keyboard virtual seluler?
Ryan Peschel

@RyanPeschel Apakah keyboard virtual itu elemen HTML (mis. div)?
Richard

Saya tidak yakin bagaimana ini dikodekan.
Ryan Peschel

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.