
Recentemente, eu estava trabalhando em algumas interfaces de bate-papo, e o layout geral é típico do que você veria na maioria dos aplicativos de bate-papo. Haveria uma entrada beijando a parte inferior da janela, com mensagens exibidas na janela de bate-papo de ambos os lados, dependendo de quem disse o quê.
Geralmente, suas próprias mensagens apareceriam à direita, enquanto as mensagens recebidas apareceriam à esquerda. Claro que também existem algumas interfaces (Slack) que alinham todas as mensagens à esquerda, mas as que uso regularmente (Whatsapp, WeChat, Twitter) usam o estilo de esquerda-direita mencionado.
Essa interface não é complicada de construir com o Flexbox e as propriedades de alinhamento de caixas. Mas eu criei um bug na interface ao usar as propriedades de alinhamento de caixas na área de mensagens. TL: DR, a correção envolve o uso de margens automáticas em vez de justify-content
. Intrigado? Leia.
CSS na interface de bate-papo
Primeiro, darei rapidamente uma ampla visão geral de como é o CSS de uma interface básica de bate-papo. Portanto, o layout deve ser algo como isto:
Você precisaria de um contêiner para toda a janela de bate-papo, dividido em um cabeçalho, uma área de mensagens e a área de entrada na parte inferior. Dentro da área de mensagens, as mensagens individuais seriam seu próprio elemento, dispostas à esquerda e à direita.
<aside id="chatWindow">
<div class="header">
<h1>Live support</h1>
<button class="btn-close" id="closeChat">
<svg viewBox="0 0 47.971 47.971"><path fill="white" d="M28.228 23.986L47.092 5.122a2.998 2.998 0 000-4.242 2.998 2.998 0 00-4.242 0L23.986 19.744 5.121.88a2.998 2.998 0 00-4.242 0 2.998 2.998 0 000 4.242l18.865 18.864L.879 42.85a2.998 2.998 0 104.242 4.241l18.865-18.864L42.85 47.091c.586.586 1.354.879 2.121.879s1.535-.293 2.121-.879a2.998 2.998 0 000-4.242L28.228 23.986z"/></svg>
</button>
</div>
<div id="message-area" class="messages">
</div>
<div class="controls">
<form id="textentry">
<input id="textbox" type="text">
<input id="submit" type="submit" value="Send">
</form>
</div>
</aside>
Neste exemplo em particular, usei um <aside>
elemento como o corpo da janela de bate-papo e apliquei um display: flex
sobre ele. Todo o layout da janela de bate-papo será desenvolvido com o Flexbox.
aside {
display: flex;
flex-direction: column;
height: 100vh;
}
.header {
display: flex; /* Because I have a close button I want aligned with the title text */
align-items: center;
/* Visual styles not included here but they exist */
}
.messages {
flex: 1; /* Allows the message area to expand with viewport height */
display: flex;
flex-direction: column;
overflow-y: scroll;
}
.controls {
/* Visual styles, not much layout */
}
A flex: 1
na área da mensagem enquanto seu pai ( <aside>
) é um contêiner flexível com uma direção flexível da coluna significa que a área da mensagem aumentará para preencher espaço adicional à medida que a altura da viewport aumentar, ou vice-versa.
O uso de um único número inteiro positivo como o flex
valor em um item flex está usando um dos valores da palavra-chave flex. Essa palavra-chave é resolvida com um flex-grow
valor qualquer que seja o número inteiro positivo, um flex-shrink
valor de 1
e um flex-basis
de 0
.
Quanto aos balões de bate-papo na área de mensagens, cada função tem sua própria classe, por exemplo, agent
e input
. Para o balão de bate-papo que deveria estar à esquerda, você realmente não precisa fazer nada e, para o balão de bate-papo que deveria estar à direita, adicione um align-self: flex-end
.
O problema de perda de dados
À medida que mais mensagens são trocadas, a altura total de todas as mensagens excederá a da área de mensagens; portanto, gostaríamos que a área de mensagens pudesse ser rolada.
Inicialmente, para que as mensagens de bate-papo iniciem na parte inferior da área de mensagens, eu havia definido um justify-content: flex-end
na área de mensagens. Isso funciona bem o suficiente. No início.
.messages {
flex: 1; /* Allows the message area to expand with viewport height */
display: flex;
flex-direction: column;
overflow-y: scroll;
justify-content: flex-end;
}
Infelizmente, quando recebemos mais mensagens do que a área de mensagens pode conter, sofremos um problema de perda de dados. Não podemos rolar para as primeiras mensagens.
Se você espreitar a especificação para o alinhamento de caixas, há este bit:
Quando o assunto do alinhamento for maior que o contêiner de alinhamento, ele transbordará. Alguns modos de alinhamento, se respeitados nesta situação, podem causar perda de dados: por exemplo, se o conteúdo de uma barra lateral estiver centralizado, quando eles excederem, poderão enviar parte de suas caixas além da borda inicial da janela de visualização , que não pode ser rolada para .
E se você olhar para a especificação do flexbox, também há este bit:
Caixas transbordando ignoram suas margens automáticas e transbordam na direção final.
Agora, se você usar a palavra-chave de alinhamento de estouro de safe
, o que o navegador fará é alterar o modo de alinhamento de volta para um que não resulte em perda de dados. E você pode tentar fazer isso no Firefox para ver por si mesmo.
.messages {
flex: 1; /* Allows the message area to expand with viewport height */
display: flex;
flex-direction: column;
overflow-y: scroll;
justify-content: safe flex-end;
}
Porém, a intenção original de iniciar as mensagens na parte inferior da área de mensagens não pode ser alcançada. O navegador forçou o alinhamento para flex-start
evitar a perda de dados, então voltamos à estaca zero.
A correção de margens automáticas
A solução que eu encontrei é que, em vez de definir a justify-content: flex-end
para alinhar as mensagens na parte inferior da área de mensagens, eu definiria margin-top: auto
o primeiro filho da área de mensagens.
Se você espiar a especificação Flexbox dessa vez, poderá encontrar este bit:
Antes do alinhamento via conteúdo justificado e auto-alinhamento, qualquer espaço livre positivo é distribuído para as margens automáticas nessa dimensão.
Independentemente de quantas bolhas de mensagem existam na área de mensagens, a margem automática superior no primeiro balão empurrará todas as mensagens para a parte inferior da área de mensagens. E quando houver muitas mensagens, você ainda poderá rolar a área de mensagens.