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, SVG 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" />
</svg>
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>
</blockquote>
Applying and scaling the SVG speech bubble is accomplished using the following CSS:
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 astroke-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
Autobots,Attack!
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