Fiz uma pergunta semelhante ontem, mas a expliquei mal e não especifiquei meu desejo por uma solução CSS pura, o que acho que deveria ser possível, então estou tentando novamente.
Basicamente, tenho um problema em que tenho uma div de mensagens roláveis e um campo de entrada abaixo dele. Quando clico em um botão, gostaria que o campo de entrada aumentasse 100 pixels, sem que a div das mensagens também fosse rolada.
Aqui está um violino que demonstra o problema em sua totalidade
Como você pode ver, quando você clica no botão "adicionar margem", a div das mensagens também é exibida. Eu gostaria que ficasse onde estava. Da mesma forma, se você estiver levemente rolado para cima para poder ver apenas a penúltima e última mensagem, clicar no botão deve manter a mesma posição ao clicar.
O interessante é que esse comportamento é "às vezes" preservado. Por exemplo, em algumas circunstâncias (que não posso deduzir), a posição de rolagem é mantida. Eu gostaria que ele se comportasse de maneira consistente como tal.
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>
div
que está rolando para cima, é a altura da div que está diminuindo. Então, por que isso importa? Bem, o que isso significa é que oscrollbar
não está ajustando sua posição. A barra de rolagem lembra apenas sua posição em relação à parte superior do contêiner. Quando a altura da div diminui, parece que a barra de rolagem está rolando para cima, mas na verdade não está.Respostas:
Esta é uma solução divertida que você pode gostar.
O que sabemos sobre a div é que ela preserva apenas a posição superior da barra de rolagem; portanto, se a altura for alterada por algum motivo, a barra de rolagem permanecerá a mesma e é isso que causa o seu problema.
Como solução alternativa, você pode girar os
.messages
180 graus usandotransform: rotate(180deg) scaleX(-1);
e retroceder.message
para cancelar o lançamento do conteúdo, e a div manterá a barra de rolagem inferior (que é a parte superior) automaticamente.fonte
O comportamento normal da barra de rolagem deve estar no topo; portanto, quando você o define na parte inferior do carregamento da página, é necessário mantê-lo, porque sempre que o conteúdo abaixo for pressionado, o div scroll será movido para o topo.
Então, eu tenho duas soluções para você:
Inverta as mensagens dentro da div de mensagens, para que a última mensagem seja a primeira, para que a rolagem esteja sempre no topo.
Eu criei uma função javascript para rolar para a parte inferior de qualquer elemento, para que você a chame sempre que quiser rolar para a parte inferior.
Verifique o trecho
fonte
Você pode fazer o contrário, dando a altura para o em
.messages
vez de dar para.container
, neste caso, não afetará as mensagens,div
mas se você estiver dando para.container
ele, ele empurrará sua div porque a margem está dentro do principal div que tem uma altura.Verifique este trecho
fonte
.send-message
. Se você olhar para a minha pergunta anterior, isso é feito porque é semelhante ao aumento de margem da abertura do teclado virtual em dispositivos móveis (a margem inferior é apenas uma substituição de 1: 1 para depurar a solução)A solução simples é definir o anterior
scrollTop
em alternância. Aqui estou usando o conjunto de dados para armazenar oscrollTop
valor anterior , você também pode usar a variávelfonte
Quero dizer, a seguir é uma solução apenas CSS que resolve exatamente o seu exemplo:
mas acho que não o ajudará com seu problema original do teclado virtual. Mas talvez isso possa inspirar outra pessoa a uma solução.
O principal problema parece ser que a barra de rolagem já está fazendo exatamente o que você deseja:
Manter sua posição para que o conteúdo lido mais recentemente seja visível.
Exceto que a barra de rolagem decide que você deseja ver a PARTE SUPERIOR do conteúdo visível no momento, não a parte inferior. (É mais fácil ver se você usa números: https://jsfiddle.net/1co3x48n/ )
Se você deseja usar o javascript, há todo tipo de respostas: https://www.google.com/search?q=scrollbar+always+on+bottom+css+site:stackoverflow.com
Honestamente, o fato de você poder passar por ~ 3 + páginas disso e encontrar apenas respostas Javascript me diz que você não encontrará uma resposta somente CSS, certamente não uma que seja amplamente compatível com o navegador.
fonte
Infelizmente, nenhuma das soluções fornecidas realmente parece funcionar. O problema com o uso
onFocus
de uma caixa de texto é que ele não será aplicado se a caixa de texto já estiver focada. Eu estou mexendo com isso há horas e a solução mais próxima que eu encontrei até agora é a seguinte:No entanto, isso parece funcionar algumas vezes. Funciona 100% do tempo ao clicar na caixa de texto, mas, por algum motivo, ao fechar o teclado virtual, funciona apenas se tiver sido rolado para cima o suficiente. Caso contrário, ele será redefinido para a mesma posição todas as vezes (próximo à parte inferior, mas não exatamente na parte inferior).
Não tenho certeza do que está causando isso. Terá que investigar mais amanhã, suponho. Este é o mais próximo até agora.
fonte
Crie um contêiner como nos exemplos acima, mas apenas altere o CSS quando começar a digitar.
Não defino a posição da barra de rolagem, basta mover todo o contêiner de mensagens para cima. Portanto, qualquer que seja sua posição de rolagem, permanecerá a mesma. Pelo menos para baixo, é claro que você não poderá ver as linhas no topo.
Você poderá ajustar o css às suas necessidades. Você pode até ficar sem JS se usar: foco ou configuração CSS ligeiramente diferente, seja criativo :)
fonte
você deve adicionar
document.querySelector(".messages").scrollTop = 10000;
àtest
função quando adicionar margem escrollTop
terminar no carregamento definidoscrolltop
e quando você adicionar margem ou remover margemscrolltop
não definir novamente, altere seu script para que fique assimfonte
Parece haver um problema com a função de alternância js. Eu mudei para um simples hide & show. Também adicionei uma largura na tag de entrada. Você também precisa adicionar uma posição: absoluta na div de envio de mensagens e inferior: 0 para que fique na parte inferior. em seguida, coloque position: relativa no contêiner para que a div de envio da mensagem permaneça dentro do contêiner. Isso significa que o contêiner de mensagens não afetará as próprias mensagens e as empurrará para cima.
fonte
Uma abordagem CSS pura e imperfeita que eu posso criar é a seguinte:
A seção superior tem um pequeno problema quando a margem existe. O truque aqui é usar margem negativa e traduzir para "rolar para cima" (não é realmente um pergaminho, apenas uma ilusão) a
wrapper
div.fonte
div
)?Pode muito simplesmente ser endereçado com nomes de âncora. Veja o violino do JS em https://jsfiddle.net/gvbz93sx/
Alteração de HTML
<a name="bottom"></a>
Mudança de JS
document.location.hash = "#bottom";
fonte