Did someone say chimichangas?

While there are a great many techniques for making speech bubbles on web pages using CSS, most tend to be either complex to create, or too simple for the expressive nature of comic book dialogue. While not without a few limits of its own, offers far more options:

Making Bubbles

Creating the bubbles is fairly straightforward in any vector graphic application: for a simple bubble I’d recommend merging an ellipse with a speech “tail” to create a single SVG path. However, the exported code does have to be treated a little carefully:

<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" 
viewBox="0 0 132 136">
    <path d="M125.2,2.8C57.6,2.8,2.8,42.1,2.8,84.6c0,33.3,33.9,61.6,81.1,72.2c2.8,27.2-2.5,71.7-16.1,88.4c20.5-23,42.4-61.8,50.4-84 c2.3,0,4.7,0.2,7,0.2c67.6,0,122.3-34.4,122.3-76.8S192.8,2.8,125.2,2.8z" />

Note the removal of the width and height attributes on the SVG, together with the addition of preserveAspectRatio="none". The latter is necessary due to the fact that we don’t know the exact dimensions of text that will be entered into the bubble, and we want the vector shape to stretch around whatever size it takes up.

The SVG is styled to help with this goal:

path { 
    fill: #fff;
    stroke: #111;
    stroke-width: 2;
    stroke-linejoin: bevel;
    vector-effect: non-scaling-stroke;

The stroke-linejoin: bevel is used to tighten the point on the tail of the speech bubble, while vector-effect: non-scaling-stroke means that the stroke will not resize with the SVG, keeping it’s thickness constant.

Method of Use

I’ll use a <blockquote> element to contain the text:

<blockquote class="bubble">
	<p>Did someone say <em>chimichangas?</em>

Applying and scaling the SVG speech bubble is accomplished using the following :

blockquote.bubble { 
    background: url(speech-bubble.svg); 
    background-position: center;
    background-size: 100% 100%;
    background-repeat: no-repeat;
    width: 25%;
    text-align: center;
    height: 0;
    padding-top: 6%;
    padding-bottom: 20%;
    box-sizing: content-box;
    line-height: 1;

The declaration uses a trick to “open” the height of the element (set to 0) with padding-bottom (and a little padding-top to push the text down), which fits the box of the element.

Other Bubbles

Over almost a century of development, comic book writers and illustrators have created a stylistic convention from various kinds of bubbles for different types of speech and narration:

Whisper Bubbles

Whisper bubbles are particularly easy in SVG, since their dashed outlines work well with stroke-dasharray:

That’s the sound of my brain

There are just two issues in this version:

  • The fill color of the SVG element must be same as the background: since SVG doesn’t yet have a stroke-position, the dashes will always appear halfway through the outline of the shape; making the fill appear odd against the background unless they are very close in color. (There is a rather complex method around this problem, but I’ll leave that for a future article).
  • Due to the use of vector-effect, the dashed strokes remain the same thickness even at small viewport sizes. This could be altered by using the SVG inline, which would allow the use of media queries to make the stroke thinner.

Radio bubbles


Radio speech bubbles - sometimes referred to as “electric” bubbles - are used for transmitted or electronic dialogue. Aside from their paths being more complex, the only other significant change here is altering the stroke-linejoin value:

path {
    stroke-linejoin: miter;

…which is used to make the outline of the speech bubble “spikier”.

Making The Bubble Text Responsive

The easiest way to scale the text inside the bubble is to scale it using vw units:

blockquote.bubble { 
    font-size: 2.2vw;

If the speech bubble was set in any kind of max-width container, you’d have to write an @media query to provide a clamp for the text at the top end.

Speech bubble samples use Nate Piekos’ excellent Sequentialist BB font

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/wMLBLK