By Craig Buckler

How to Create CSS3 Speech Bubbles Without Images

By Craig Buckler

I remember my creating my first image-less speech bubble many years ago. It required a long-winded JavaScript function to inject elements into the DOM, some horrendous CSS, looked fairly awful, and didn’t work well in IE5.

CSS3 is starting to change our lives for the better. It’s now possible to create a great looking speech bubble which works in all browsers, uses a single HTML element, a few lines of CSS3 code, no images, and no JavaScript whatsoever…

CSS3 speech bubble

To ease you in gently, let’s examine the HTML. A single element is required, so I’m using a P tag:

<p class="speech">SitePoint Rocks!</p>

First, we’ll style the outer box:

p.speech {
  position: relative;
  width: 200px;
  height: 100px;
  text-align: center;
  line-height: 100px;
  background-color: #fff;
  border: 8px solid #666;
  -webkit-border-radius: 30px;
  -moz-border-radius: 30px;
  border-radius: 30px;
  -webkit-box-shadow: 2px 2px 4px #888;
  -moz-box-shadow: 2px 2px 4px #888;
  box-shadow: 2px 2px 4px #888;

Nothing too complicated there. The only essential property is position: relative which is necessary for the speech bubble pointer. We also require Mozilla and Webkit vendor prefixes for border-radius and box-shadow to ensure they work in all CSS3 browsers. IE8 and below will show squared corners and no shadow, but the box will still be visible.

CSS3 speech bubble

Now we need to create the triangular bubble pointer. Rather than resorting to images, we can use CSS borders to create any type of triangle. As a brief explanation, examine an element with wide differently-colored borders:

CSS3 border triangles

If we reduce the width and height of our element to 0px and use different sized borders, we can see different triangles being formed:

CSS3 border triangles

For our speech bubble pointer, we can therefore use a solid top and left border with transparent right and bottom borders:

CSS3 border triangles

But what do we assign those border properties to? Fortunately, we can use the CSS :before and :after pseudo-elements to generate two more content items. Therefore:

p.speech:before {
  content: ' ';
  position: absolute;
  width: 0;
  height: 0;
  left: 30px;
  top: 100px;
  border: 25px solid;
  border-color: #666 transparent transparent #666;

The triangle is positioned at the bottom of our bubble. Incidentally, don’t bother trying to apply a shadow to this element — it’ll be shown around the transparent borders rather than the visible triangle.

CSS3 speech bubble

We must now remove a section of this triangle. We can position a smaller white triangle over the gray one to achieve that effect:

p.speech:after {
  content: ' ';
  position: absolute;
  width: 0;
  height: 0;
  left: 38px;
  top: 100px;
  border: 15px solid;
  border-color: #fff transparent transparent #fff;

Our pure CSS3 image-less speech bubble is complete.

CSS3 speech bubble

In essence, we can utilize the :before and :after pseudo-elements to create many different effects. For example, a thought bubble can be created with two content items rounded into circles:

p.thought {
  position: relative;
  width: 130px;
  height: 100px;
  text-align: center;
  line-height: 100px;
  background-color: #fff;
  border: 8px solid #666;
  -webkit-border-radius: 58px;
  -moz-border-radius: 58px;
  border-radius: 58px;
  -webkit-box-shadow: 2px 2px 4px #888;
  -moz-box-shadow: 2px 2px 4px #888;
  box-shadow: 2px 2px 4px #888;

p.thought:before, p.thought:after {
  left: 10px;
  top: 70px;
  width: 40px;
  height: 40px;
  background-color: #fff;
  border: 8px solid #666;
  -webkit-border-radius: 28px;
  -moz-border-radius: 28px;
  border-radius: 28px;

p.thought:after {
  width: 20px;
  height: 20px;
  left: 5px;
  top: 100px;
  -webkit-border-radius: 18px;
  -moz-border-radius: 18px;
  border-radius: 18px;

CSS3 thought bubble

Please see the demonstration page for an example which uses these techniques. All the CSS code is contained in the HTML source.

Have you used similar techniques to create other effects?

If you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Learn CSS3.

Comments on this article are closed. Have a question about CSS3? Why not ask it on our forums?

  • Deb S

    Brilliant! – Shame about the shadow (lack of) on the pseudo-elements, still, you can’t have it all!

  • Ganbold

    That was very cool tut.

  • Gaurav Mishra

    ‘I think’ was pretty different.

  • Filippo Buratti

    congratulations, really simple, brilliant and beautiful!

  • Mo

    Really cool. I shall use it. Many thanks

  • bobby

    very good, nice short lesson.

  • McBenny

    Hey, nice effect ! But it’s not very flexible as you did it.
    If you position the :before and :after with a top position, any resize of the bubble will break the design.
    If you position them like :
    p.speech:before {
    bottom: -50px;
    p.speech:after {
    bottom: -30px;
    they place themselves the same way but your bubble can grow. Of course, this is valuable if you also replace the height property of the bubble with a min-height property, that becomes very flexible.
    What do you think of it ?

  • powerpotatoe

    I love seeing & learning the simple tricks of CSS3. However, with IE’s lack of support I’m not too interested in spending the time to implement CSS3 features on my designs. Much of my web audience uses IE. I have not tried this on IE9 yet. Will it work?

    Is there a similar way to create these effects in IE7 and 8? And by similar, I mean another, more convenient method besides the standard old practice of images.

    • It works fine in IE9.

      It also works in IE8, except that you don’t get rounded corners or a shadow. The speech bubble looks fine but the thought bubble looks a little blocky.

      IE6 and IE7 just show the squared outer box.

      • kaf

        I call that a graceful degradation.


  • Karthik

    Great tips and helpful stuff!

    Cogzidel Templates

  • JT

    This has been out for about 3 years hehe.
    Catch up bro

  • Andy Read

    These are clever and fun hacks, but let’s not kid ourselves: they are definitely hacks and are ‘abusing’ the semantics of CSS!

    Creating triangles with bits of over-sized border: ingenious, but it’s just wrong, I’m afraid! As far as I can see, w3c does not define how different coloured borders should join at corners. It certainly explicitly states that it doesn’t define how different border styles should join at corners (, so a browser could be fully compliant and not create triangles – and why should it! It’s hardly the intended semantics of ‘border’.

    The use of :before and :after is also mis-using two different semantics just to means ‘append’. At a push, I’d be happier with the semantics ‘:before’ and ‘:before :before’ if that works – at least it reflects the progression of the thought bubbles :-)

    I’m not trying to be overly critical, but CSS is an important step towards the semantic web and so instead of hacks like these we should be pushing for the future (CSS4?). Just like we’ve introduced semantic effects like drop-shadow, rounded-corners, inset, dash, etc. the next generation needs to add common iconic forms like ‘speech-bubble’ and ‘thought-bubble’ with parameters such as origin and offset.

    This technique would probably score well in a code obfuscation competition, though :-)


    • Abusing the semantics of CSS? That’s a new one on me!

      Of course, you’re free to wait until CSS47 has a speech-bubble property, but it’s not likely to happen soon. If we go with current technologies, the alternatives to this solution are additional elements (semantically worse), images (increased bandwidth), or JavaScript (could be disabled).

      • Chris

        @Craig, I do understand your point about CSS47, and I will personally be using this technique (as it does look good and degrade gracefully).

        But surely you must admit that the point Andy made is quite valid (although the use of the word semantic is wrong). Borders are not intended to be used as triangles?

    • Andy mentioned that he’d like a speech/thought bubble property in CSS. I don’t think that’s likely — not soon anyway.

      Border effects like this have been used for many years and all the browsers support them (including IE6). They’re not a hack and I can’t really see them causing a problem.

  • ben

    Reminds me of CSS polygons (, though i appreciate the use of :before and :after in the article to limit the number of elements needed.

  • Neil

    These are pretty innovative. Might use these in an upcoming site.


  • cat

    Great info and nice presentation Craig. Thanks!

  • Robert

    I used a similar approach on awhile back, though I just used DIVs for the tail since IE7 doesn’t do :after / :before. I used dd_roundies to do the IE7/8 side of things, but you can hack your own VML code for that if you’re feeling frisky.

  • Jesse

    This is great. I’m still learning and trying to get better at coding.

    It only took me about 10 minutes to punch everything in.

    I guess I do have one question.

    What are CSS pseudo elements and why and how can these be used?


  • Rudie

    Very cool! Love the triangle technique.

  • andrej

    brilliant idea :)

  • Neuroflux

    Possibly this will help as well for people viewing this:

  • Alison Garnham

    My speech bubble looks fine. My thought bubble does not have the circles in front of it (in Opera and Firefox). I’ve checked the code and have no idea why. Any ideas?

  • Edwin

    I’m having the same problem. No bubbles in front of it.

  • Please publish your code somewhere and I’ll take a look.

    As a thought, have you copied the code from the example above? Note there’s a scrollbar and more code appears below. If in doubt, look at the source of the demonstration page.

  • Paul Lempke

    I think a simple vector graphic would be just as (nearly as?) compact and more generally useful . . .

    • It would be. Unfortunately, most people (IE8 users and below) wouldn’t be able to see it. Also, only the most recent browsers support SVGs as background images.

  • Randal

    Great! Think I will be using this soon in some of my sites.

  • L L

    lovely, but I can’t get the second effect accurately,no circles …

  • Michael Hall

    i like the technique but i’ve never used the :before and :after and agree witht he other commenter that it’s too much hacking.

    i’d rather just create a div or use an image that is positioned.

    but very interesting tutorial.

    • It’s not a hack — not in the traditional browser bug sense anyway. It’s fully documented CSS behavior so it shouldn’t cause any problems. It’s certainly no worse than adding unnecessary HTML elements.

    • Allen

      Craig is right in that it’s not a hack. Perhaps it is flexing the spec a bit to accomplish something other than what was originally intended when the functionality was created… but that is still not a hack. A hack, by definition, is exploiting a flaw or bug in a spec or browser to obtain the desired result. If we didn’t push the boundaries of the spec we would never make any progress on the web and everything would still be in tables.

  • Cool

Get the latest in Front-end, once a week, for free.