Div rolável para ficar no fundo, quando div externo muda de tamanho

Aqui está um exemplo de aplicativo de bate-papo ->

A ideia aqui é que o .messages-container ocupe o máximo possível da canvas. Dentro de .messages-container , .scroll mantém a lista de mensagens e, caso haja mais mensagens, o tamanho da canvas será exibido.

Agora, considere este caso:

  1. O usuário rola para o final da conversa
  2. A .text-input , dinamicamente fica maior

Agora, em vez de o usuário permanecer rolado até a parte inferior da conversa, a input de texto aumenta e eles não veem mais a parte inferior.

Uma maneira de consertar isso, se estivermos usando reagir, calcule a altura da input de texto, e se algo mudar, deixe .messages-container saber

 componentDidUpdate() { window.setTimeout(_ => { const newHeight = this.calcHeight(); if (newHeight !== this._oldHeight) { this.props.onResize(); } this._oldHeight = newHeight; }); } 

Mas, isso causa problemas de desempenho visíveis, e é triste passar mensagens assim.

Existe uma maneira melhor? Eu poderia usar o css de tal forma, para expressar que quando .texto de input aumenta, eu quero essencialmente shift up todos os .messages-container

2: nd revisão desta resposta

Seu amigo aqui é flex-direction: column-reverse; que faz tudo o que você pede enquanto alinha as mensagens na parte inferior do contêiner de mensagens, assim como, por exemplo, o Skype e muitos outros aplicativos de bate-papo.

 .chat-window{ display:flex; flex-direction:column; height:100%; } .chat-messages{ flex: 1; height:100%; overflow: auto; display: flex; flex-direction: column-reverse; } .chat-input { border-top: 1px solid #999; padding: 20px 5px } .chat-input-text { width: 60%; min-height: 40px; max-width: 60%; } 

A desvantagem com flex-direction: column-reverse; é um bug no IE / Edge / Firefox, onde a barra de rolagem não aparece, o que você pode ler mais aqui: Flexbox reverse e overflow no Firefox / IE

A vantagem é que você tem ~ 90% de suporte a navegadores em dispositivos móveis / tablets e ~ 65% em computadores, e contando que o bug seja corrigido, … e há uma solução alternativa.

 // scroll to bottom function updateScroll(el){ el.scrollTop = el.scrollHeight; } // only shift-up if at bottom function scrollAtBottom(el){ return (el.scrollTop + 5 >= (el.scrollHeight - el.offsetHeight)); } 

No trecho de código abaixo, adicionei as duas funções acima, para fazer o IE / Edge / Firefox se comportar da mesma maneira como flex-direction: column-reverse; faz.

 function addContent () { var msgdiv = document.getElementById('messages'); var msgtxt = document.getElementById('inputs'); var atbottom = scrollAtBottom(msgdiv); if (msgtxt.value.length > 0) { msgdiv.innerHTML += msgtxt.value + '
'; msgtxt.value = ""; } else { msgdiv.innerHTML += 'Long long content ' + (tempCounter++) + '!
'; } /* if at bottom and is IE/Edge/Firefox */ if (atbottom && (!isWebkit || isEdge)) { updateScroll(msgdiv); } } function resizeInput () { var msgdiv = document.getElementById('messages'); var msgtxt = document.getElementById('inputs'); var atbottom = scrollAtBottom(msgdiv); if (msgtxt.style.height == '120px') { msgtxt.style.height = 'auto'; } else { msgtxt.style.height = '120px'; } /* if at bottom and is IE/Edge/Firefox */ if (atbottom && (!isWebkit || isEdge)) { updateScroll(msgdiv); } } /* fix for IE/Edge/Firefox */ var isWebkit = ('WebkitAppearance' in document.documentElement.style); var isEdge = ('-ms-accelerator' in document.documentElement.style); var tempCounter = 6; function updateScroll(el){ el.scrollTop = el.scrollHeight; } function scrollAtBottom(el){ return (el.scrollTop + 5 >= (el.scrollHeight - el.offsetHeight)); }
 html, body { height:100%; margin:0; padding:0; } .chat-window{ display:flex; flex-direction:column; height:100%; } .chat-messages{ flex: 1; height:100%; overflow: auto; display: flex; flex-direction: column-reverse; } .chat-input { border-top: 1px solid #999; padding: 20px 5px } .chat-input-text { width: 60%; min-height: 40px; max-width: 60%; } /* temp. buttons for demo */ button { width: 12%; height: 44px; margin-left: 5%; vertical-align: top; } /* begin - fix for hidden scrollbar in IE/Edge/Firefox */ .chat-messages-text{ overflow: auto; } @media screen and (-webkit-min-device-pixel-ratio:0) { .chat-messages-text{ overflow: visible; } /* reset Edge as it identifies itself as webkit */ @supports (-ms-accelerator:true) { .chat-messages-text{ overflow: auto; } } } /* hide resize FF */ @-moz-document url-prefix() { .chat-input-text { resize: none } } /* end - fix for hidden scrollbar in IE/Edge/Firefox */ 
 
Long long content 1!
Long long content 2!
Long long content 3!
Long long content 4!
Long long content 5!

Você só precisa de um conjunto de regras CSS:

 .messages-container, .scroll {transform: scale(1,-1);} 

É isso aí, está feito! Isso manterá a conversa rolada para baixo, com a última mensagem em exibição, independentemente de qualquer redimensionamento do contêiner, checkbox de input ou qualquer outra coisa. Funciona em todos os navegadores modernos.

Como funciona: Primeiro, ele inverte verticalmente o elemento externo messages-container (que manipula a rolagem) para que a parte superior se torne a parte inferior. Em seguida, ele inverte o elemento de scroll interno para que as mensagens não fiquem de cabeça para baixo.

Essa abordagem tem um efeito colateral estranho: quando você usa uma roda do mouse (ou algo que emula um) na checkbox de mensagem, a direção de rolagem é invertida. Se isso incomoda você, você pode corrigi-lo com JavaScript (como mostrado abaixo).

Aqui está uma demonstração e um jsfiddle para brincar:

 //Reverse wheel direction document.querySelector('.messages-container').addEventListener('wheel', function(e) { if(e.deltaY) { e.preventDefault(); e.currentTarget.scrollTop -= parseFloat(getComputedStyle(e.currentTarget).getPropertyValue('font-size')) * (e.deltaY < 0 ? -1 : 1) * 2; } }); //The rest of the JS just handles the test buttons and is not part of the solution send = function() { var inp = document.querySelector('.text-input'); document.querySelector('.scroll').insertAdjacentHTML('beforeend', '

' + inp.value); inp.value = ''; inp.focus(); } resize = function() { var inp = document.querySelector('.text-input'); inp.style.height = inp.style.height === '50%' ? null : '50%'; }

 html,body {height: 100%;margin: 0;} .conversation { display: flex; flex-direction: column; height: 100%; } .messages-container { flex-shrink: 10; height: 100%; overflow: auto; } .messages-container, .scroll {transform: scale(1,-1);} .text-input {resize: vertical;} 
 

Message 1

Message 2

Message 3

Message 4

Message 5

Message 6

Message 7

Message 8

Message 9

Message 10

Por favor, tente o seguinte violino – https://jsfiddle.net/Hazardous/bypxg25c/ . Embora o violino esteja atualmente usando o jQuery para aumentar / resize a área de texto, o crux está nos estilos relacionados ao flex usados ​​para as classs container de mensagens e container de input –

 .messages-container{ order:1; flex:0.9 1 auto; overflow-y:auto; display:flex; flex-direction:row; flex-wrap:nowrap; justify-content:flex-start; align-items:stretch; align-content:stretch; } .input-container{ order:2; flex:0.1 0 auto; } 

O valor flex-shrink é definido como 1 para .messages-container e 0 para .input-container. Isso garante que o contêiner de mensagens seja reduzido quando houver uma realocação de tamanho.

Mudei text-input nas messages , coloquei-a na parte inferior do contêiner e dei a messages suficiente para espaço de acordo.

Execute algum código para adicionar uma class à conversation , o que altera a altura da text-input de text-input e do preenchimento das messages usando uma agradável animação de transição CSS.

O JavaScript executa uma function “scrollTo” ao mesmo tempo em que a transição de CSS é executada para manter a rolagem na parte inferior.

Quando o pergaminho sai do fundo novamente, removemos a class da conversation

Espero que isto ajude.

https://jsfiddle.net/cnvzLfso/5/

 var doScollCheck = true; var objConv = document.querySelector('.conversation'); var objMessages = document.querySelector('.messages'); var objInput = document.querySelector('.text-input'); function scrollTo(element, to, duration) { if (duration < = 0) { doScollCheck = true; return; } var difference = to - element.scrollTop; var perTick = difference / duration * 10; setTimeout(function() { element.scrollTop = element.scrollTop + perTick; if (element.scrollTop === to) { doScollCheck = true; return; } scrollTo(element, to, duration - 10); }, 10); } function resizeInput(atBottom) { var className = 'bigger', hasClass; if (objConv.classList) { hasClass = objConv.classList.contains(className); } else { hasClass = new RegExp('(^| )' + className + '( |$)', 'gi').test(objConv.className); } if (atBottom) { if (!hasClass) { doScollCheck = false; if (objConv.classList) { objConv.classList.add(className); } else { objConv.className += ' ' + className; } scrollTo(objMessages, (objMessages.scrollHeight - objMessages.offsetHeight) + 50, 500); } } else { if (hasClass) { if (objConv.classList) { objConv.classList.remove(className); } else { objConv.className = objConv.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); } } } } objMessages.addEventListener('scroll', function() { if (doScollCheck) { var isBottom = ((this.scrollHeight - this.offsetHeight) === this.scrollTop); resizeInput(isBottom); } }); 
 html, body { height: 100%; width: 100%; background: white; } body { margin: 0; padding: 0; } .conversation { display: flex; flex-direction: column; justify-content: space-between; height: 100%; position: relative; } .messages { overflow-y: scroll; padding: 10px 10px 60px 10px; -webkit-transition: padding .5s; -moz-transition: padding .5s; transition: padding .5s; } .text-input { padding: 10px; -webkit-transition: height .5s; -moz-transition: height .5s; transition: height .5s; position: absolute; bottom: 0; height: 50px; background: white; } .conversation.bigger .messages { padding-bottom: 110px; } .conversation.bigger .text-input { height: 100px; } .text-input input { height: 100%; } 
 

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is a message content

This is the last message

Você escreve;

 Now, consider this case: The user scrolls to the bottom of the conversation The .text-input, dynamically gets bigger