Auralinna.blog Tero Auralinna's blog about intriguing world of web development. Tweaking pixels since the '90s.

How to make a CSS speech bubble with borders and drop shadow

Published on December 22, 2017. Edited on April 26, 2020.

Here is an example of how to create a CSS speech bubble with borders and drop shadow.

The code snippet at CodePen to play around with chat bubble styles.

Embedded content: https://codepen.io/teroauralinna/pen/JMKyeB

Simple speech bubble

Let's start by creating a simple one with just rounded corners and arrow.

HTML code

We need just one div to create a simple speech bubble. Although <blockquote> is more semantic element in case you're using the bubble for somebody's comment.

<div class="speech-bubble">
  <p><strong>Demo speech bubble</strong></p>
  <p>This is a simple CSS speech bubble.</p>
</div>

SCSS

.speech-bubble {
  background: #efefef;
  border-radius: 4px;
  font-size: 1.2rem;
  line-height: 1.3;
  margin: 0 auto 40px;
  max-width: 400px;
  padding: 15px;
  position: relative;

  p {
    margin: 0 0 10px;

    :last-of-type {
      margin-bottom: 0;
    }
  }

  &::after {
    border-left: 20px solid transparent;
    border-top: 20px solid #efefef;
    bottom: -20px;
    content: "";
    position: absolute;
    right: 20px;
  }
}

Speech bubble with borders and drop shadow

Now we have a base for our speech bubble. Let's add borders and drop shadow next. We need to add a new HTML element for the arrow because we need to simulate borders and drop shadow with other elements.

HTML

Let's add HTML element <div class="speech-bubble-ds-arrow"></div> for arrow.

<div class="speech-bubble-ds">
  <p><strong>Demo speech bubble</strong></p>
  <p>This is CSS speech bubble with borders and drop shadow.</p>
  <div class="speech-bubble-ds__arrow"></div>
</div>

SCSS

CSS is a little bit more complex here because we need to use ::before and ::after pseudo-elements. Class .speech-bubble-ds__arrow will be used for the shadow of the arrow and .speech-bubble-ds-arrow::before will be used for the border. Pseudo-element .speech-bubble-ds__arrow::after will be the arrow.

.speech-bubble-ds {
  background: #efefef;
  border: 1px solid #a7a7a7;
  border-radius: 4px;
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.2);
  font-size: 1.2rem;
  line-height: 1.3;
  margin: 0 auto 40px;
  max-width: 400px;
  padding: 15px;
  position: relative;

  p {
    margin-bottom: 10px;

    :last-of-type {
      margin-bottom: 0;
    }
  }
}

.speech-bubble-ds__arrow {
  border-left: 21px solid transparent;
  border-top: 20px solid rgba(0, 0, 0, 0.2);
  bottom: -25px;
  position: absolute;
  right: 15px;

  &::before {
    border-left: 23px solid transparent;
    border-top: 23px solid #a7a7a7;
    bottom: 2px;
    content: "";
    position: absolute;
    right: 5px;
  }
  &::after {
    border-left: 21px solid transparent;
    border-top: 21px solid #efefef;
    bottom: 4px;
    content: "";
    position: absolute;
    right: 6px;
  }
}

You can modify arrow border values or absolute positioning to change arrow size or position.