CSS Tutorial: Speech Balloon Tail


Glitch Witch
Wanna learn how to make this in CSS?
It involves a trick using box-shadow.

Here's a JSFiddle with all the code for you to mess around with (make sure to click the Run button on the top left to see your changes)

This is how it works:
  1. Make sure your main box has position: relative, so that anything absolute positioned within there will be positioned relative to the box rather than the entire window.
  2. Create a tail div within that box, use position: absolute on it + negative values for bottom and left to extend it beyond the bottom left corner of the box.
  3. Give that #tail a height, width, border-bottom-right-radius, overflow: hidden (necessary for the trick), and some rotation with transform: rotate.
  4. Notice how we don't give the tail div a background color, because we're actually just using it to define the bounds for the tail (which is why we need overflow: hidden to clip the contents to the border radius.
  5. Define the pseudo-element #tail::after, giving it a content: '' (otherwise the pseudo-element won't display anything).
  6. Give #tail::after position: absolute, negative left (important to create the tail point), bottom: 0.
  7. Give #tail::after a height, width, and the same border-bottom-right-radius as the tail div.
  8. Now for the magic: add box-shadow: 0 0 0 10px color to tail::after, replacing color with whatever color the box is. This spreads the box shadow by 10px in all directions, which just fills in the space between #tail::after and #tail, creating the tail.

This works with any background, including transparent, since no background color was ever given to #tail!

By giving #tail background-color: black and border: 1px solid black, you can see how this illusion is pulled off.
Bonus: Opacity

If you set the background color of the box and tail to be semi-transparent, you get an overlap at the bottom left, like this:
To avoid that, just set an opacity value on the #box itself, like opacity: 0.5
This will make everything in the box semi-transparent, including the text, but you can get around by having the background and the text be on separate layers within another div.