그 아래 div에 부딪 쳤을 때 div 스크롤을 방지합니까?


10

내가 물었다 비슷한 질문을 어제하지만 가난을 설명하고, 내가 다시 노력하고, 그래서 가능해야한다고 생각 순수 CSS 솔루션에 대한 내 욕망을 지정하지 않았습니다.

기본적으로 스크롤 가능한 메시지 div와 그 아래에 입력 필드가있는 문제가 있습니다. 버튼을 클릭하면 메시지 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

답변:


5

이것은 당신이 좋아할만한 재미있는 솔루션입니다.

우리가 div에 대해 알고있는 것은 스크롤 막대의 상단 위치 만 유지하므로 어떤 이유로 인해 높이가 변경되면 스크롤 막대가 동일하게 유지되어 문제가 발생합니다.

해결 방법으로 내용을 뒤집기를 취소 하려면 을 .messages사용하여 180도를 transform: rotate(180deg) scaleX(-1);뒤집고 뒤로 뒤집을 수 있습니다 .div .message는 아래쪽 스크롤 막대 (상단)를 자동으로 유지합니다.

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. 모든 요소의 맨 아래로 스크롤하는 자바 스크립트 함수를 만들었으므로 맨 아래로 스크롤 할 때마다 호출하면됩니다.

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에서 : "유사하게 약간 위로 스크롤하여 두 번째에서 마지막 메시지 만 볼 수있는 경우 버튼을 클릭하면 클릭시 해당 위치를 유지해야합니다."
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;}

하지만 가상 키보드의 원래 문제를 해결하는 데 도움이되지는 않습니다. 그러나 이것은 아마도 다른 사람에게 해결책을 줄 수 있습니다.

주요 문제는 스크롤 막대가 이미 원하는 것을 정확하게 수행하는 것 같습니다.

가장 최근에 읽은 컨텐츠를 볼 수 있도록 위치를 유지하십시오.

스크롤바를 제외하고는 맨 아래가 아니라 현재 표시된 컨텐츠의 TOP을 보겠다고 결정합니다. (숫자를 사용하는 것이 더 쉽습니다. https://jsfiddle.net/1co3x48n/ )

자바 스크립트를 사용하려는 경우 모든 종류의 답변이 있습니다. 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 Berlin

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와 bottom : 0에 position : absolute를 추가해야합니다. 따라서 맨 아래에 유지됩니다. 그런 다음 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.