CSS3 Chat Bubbles with Flex

by Leandro Barbosa

HTML

<div class="wrap">
  <div id="chatWindow" class="container">
    <div class="bubble left">
      <p>msg</p>
    </div>
    <div class="bubble left">
      <p>long message</p>
    </div>
    <div class="bubble right">
      <p>ultra long message which can wrap at eighty percent long message which can wrap at eighty percent </p>
    </div>
    <div class="bubble left">
      <p>lorem ipsum</p>
    </div>
    <div class="bubble right">
      <p>very long message</p>
    </div>
    <div class="bubble right">
      <p>one more message</p>
    </div>
    <div class="bubble left">
      <p>lorem ipsum</p>
    </div>
    <div class="bubble right">
      <p>another message</p>
    </div>
    <div class="bubble left">
      <p>lorem ipsum</p>
    </div>
    <div class="bubble right">
      <p>yet another message</p>
    </div>
    <div class="bubble left">
      <p>lorem ipsum</p>
    </div>
  </div>
  <div id="inputWindow" class="form">
    <input id="inp" type="text" />
    <div>
      <input id="btn" type="button" value="Send" />
    </div>
  </div>
</div>

SCSS

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html,
body {
  height: 100%;
  overflow: hidden;
}

.wrap {
  padding: 15px;
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
}

.container {
  flex: 1 1 90%;
  display: flex;
  flex-direction: column-reverse;
  background-color: #eee;
  border: 1px solid red;
  overflow: auto;
}

.form {
  flex: 0 0 10%;
  display: flex;
  border: 1px solid blue;
  max-height: 32px;

  input[type=text] {
    flex: 1 1 auto;
    border: 1px solid #eee;
  }

  input[type=button] {
    flex: 0 0 20%;
    border: 1px solid #eee;
  }
}

.bubble {
  flex: 1 1 auto;
  clear: both;

  p {
    border-radius: 5px;
    padding: 8px;
    margin: 8px 12px;
    max-width: 80%;
    position: relative;
    transition: background-color 0.5s;
  }

  &.left p {
    background-color: #ccc;
    float: left;

    &::before {
      content: '';
      position: absolute;
      width: 0;
      height: 0;
      left: -8px;
      top: 8px;
      border-top: 4px solid transparent;
      border-right: 8px solid #ccc;
      border-bottom: 4px solid transparent;
    }
  }

  &.right p {
    background-color: #33c;
    color: #fff;
    float: right;

    &::after {
      content: '';
      position: absolute;
      width: 0;
      height: 0;
      right: -8px;
      bottom: 8px;
      border-top: 4px solid transparent;
      border-left: 8px solid #33c;
      border-bottom: 4px solid transparent;
    }
  }
}

JavaScript

var btn = document.getElementById('btn'),
  inp = document.getElementById('inp'),
  chats = document.getElementById('chatWindow');

btn.addEventListener('click', postMsg);

inp.addEventListener('keyup', function(e) {
  if (e.keyCode == 13) {
    postMsg();
  }
});

function postMsg() {
  var msg = inp.value,
    bubble = document.createElement('div'),
    p = document.createElement('p');
  if (msg.trim().length <= 0) {
    return;
  }
  bubble.classList.add('bubble');
  bubble.classList.add('right');
  p.textContent = msg;
  bubble.append(p);
  inp.value = '';
  chats.insertBefore(bubble, chats.firstChild);
  
  rcvdMsg();
}

function rcvdMsg() {
  var msg = "what?",
    bubble = document.createElement('div'),
    p = document.createElement('p');
  if (msg.trim().length <= 0) {
    return;
  }
  bubble.classList.add('bubble');
  bubble.classList.add('left');
  p.textContent = msg;
  bubble.append(p);
  chats.insertBefore(bubble, chats.firstChild);
}