Aguarde...

31 de outubro de 2019

Alinhamento e estouro de caixas

Alinhamento e estouro de caixas

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: flexsobre 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 */
}

flex: 1na á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 flexvalor em um item flex está usando um dos valores da palavra-chave flex. Essa palavra-chave é resolvida com um flex-growvalor qualquer que seja o número inteiro positivo, um flex-shrinkvalor de 1e um flex-basisde 0.

Quanto aos balões de bate-papo na área de mensagens, cada função tem sua própria classe, por exemplo, agentinput. 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-endna á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-startevitar 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-endpara alinhar as mensagens na parte inferior da área de mensagens, eu definiria margin-top: autoo 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.

Postado em Blog
Escreva um comentário