Grow your CSS skills. Land your dream job.

Speech Bubble Arrows that Inherit Parent Color

Published by Chris Coyier

Interesting question:


By "css3 speech bubble", Jin means using a pseudo element on a container to add a little pointer arrow (triangle). Not really CSS3, but that's pedantic.

Let's say that pink color isn't practical to set in an external CSS file. Perhaps is a user setting, or perhaps its set dynamically somehow.

<div class="speech-bubble" style="background: pink;">
   I like bananas, because they have no bones.
</div>

Setting the container with an inline style is all well and good, but unfortunately there is no inline style for pseudo elements. So we might end up with something like this:

Bummer.

There is a solution though! While we are setting the inline style for the container, we can set an inline style for border-color too. Even though the container actually has no border, we can rely on inheritance to pass that color down to the pseudo element, which is treated like a child element.

<div class="speech-bubble" style="border-color: pink; background: pink;">
   I like bananas, because they have no bones.
</div>

Then in our code for the pseudo element, we'll specifically have it inherit the color:

.speech-bubble:after {
   content: "";
   position: absolute;
   top: 100%;
   left: 20px;
   border-top: 20px solid black;
   border-top-color: inherit; 
   border-left: 20px solid transparent;
   border-right: 20px solid transparent; 
}

Notice that I've applied inherit to border-top-color rather than the shorthand property border-top. For some reason (feel free to enlighten me) inherit doesn't work in the shorthand. Also note that when you override the the color with inherit, it doesn't "inherit" from the color set just above it (black), it inherits from its parent. So if you need a default, you'll need to set the border-color on the parent.

View Demo

Comments

  1. Untit1ed
    Permalink to comment#

    By replacing pseudo element with a span element you make it compatible with IE7 and IE8 browsers.

    • Just IE 7 actually, IE 8 had pseudo elements. But yes correct. AND you’d have to worry less about this inheritance business, since you could set the border color right on the span. But then you have non-semantic markup.

    • Untit1ed
      Permalink to comment#

      well, semantics are good, but it my project I had to use this technique for showing tool-tips, and I realized that I wasn’t able to manipulate pseudo element’s styles through JavaScript (I was trying to adjust that little triangle position). So I guess it all depends on what you’re doing with it.

    • Permalink to comment#

      I think there would be a javascript way to test if the browser supports pseudo elements, and if it doesn’t append a <span> element. Then, when styling simple do:

      .bubble::after,
      .bubble span {
      border-top-color: inherit; /* I didn't actually test this but in theory it should work */
      }

    • Permalink to comment#

      Forgive my typos…

    • Permalink to comment#

      Anyone know of a way to find all elements with :before or :after content using javascript? I looked around for a while and couldn’t find one. This would make it possible to do something like:

      .selector:before,
      .selector .before {
          content: '\a0';
          ...other stuff....
      }
      

      Then use your javascript to add a span inside the element….boom, ie7 support.

      I currently do this manually by just knowing which elements I am using :before and :after on, but that is less the best practice…

  2. I’m impressed with the verbiage – “I like bananas, because they have no bones.” Thanks for the laugh!

  3. Comes handy also in normal usage. Thanks!

  4. Max Terpstra
    Permalink to comment#

    If you don’t care about old browser support, simply inherit the background color and rotate the box 45°.

    For older browsers, you might also be able to get away with masking the background into a triangle shape with solid color borders. This would require having a known background color that the bubbles will be floating over though.

    • Can’t we use a pseudo element which is a box rotated 45° and inheriting the background colour (with positioning to look like a triangle, i.e., half of the box will overlap with the bubble to make the box look like a triangle protruding out)?

  5. cnwtx
    Permalink to comment#

    Wouldn’t it be nice if this worked:

    div {
         . . .
         background:attr(data-background);
    }
    
    div.bubble:before {
         . . . 
         background:attr(data-background);
    }

    Does anyone know of a way to make it work?

    • I think it is not possible if it’s done purely by CSS. And if I could use javascript, I still can’t select the div.bubble:before. Unless that you insert another extra element with javascript. And I think you don’t need a data-background attribute. Just get the background-color value:

      $(function() {
         $('div.bubble').append('<span></span>');
         $('span', 'div.bubble').css('border-top-color', $(this).parent().css('background-color'));
      });

      Am I wrong?

    • Permalink to comment#

      It can be done by pure CSS in future, but not now.
      http://dev.w3.org/csswg/css-variables/

    • Permalink to comment#

      Or if you’re using SCSS or a comparable extension, you can do it now.

  6. Great tip, thanks Chris.

    By the way, love ShopTalk!

  7. .speech-bubble – shouldn’t it have a line “position: relative;”?

  8. TipperCrew
    Permalink to comment#

    Very userful tip.

    Thanks!

  9. Maksim Chemerisuk
    Permalink to comment#

    Hi, Chris. There is a reduced version of the second css rule:

    .bubble:after {
        content: "";
        position: absolute;
        top: 100%;
        left: 20px;
        border: 20px solid transparent;
        border-top-color: inherit; 
    }

    Thanks for sharing this fresh idea.

  10. sky
    Permalink to comment#

    May be wikll be possible and with ‘currentColor’ ? :P)

  11. “I like bananas, because they have no bones.” from the man himself… Mr Robyn Hitchcock!

  12. ups
    Permalink to comment#

    sorry, only a test of your great form

  13. StevenJ
    Permalink to comment#

    Excellent article, thanks a learn some amazing tricks.

  14. tnx Chris, this is exactly what i was looking for :)

  15. I didn’t quite understand which part of the code is responsible for the triangle thingy… Is it the “transparent” keyword?

  16. please can you Chris let us know how this trialing created
    i cant see where did you created in your code !!

  17. Permalink to comment#

    Strange bug in FF:

    Just try this
    style=”background: white; border-color: white;”
    (or any light color)

    instead of this
    style=”background: red; border-color: red;”

    The triangle will get a thin dark outline. Has anybody a fix for that?

    So now I have to use this “content: ‘\a0′;”

    • Permalink to comment#

      … and here ist the answer to the FF bug:

      <code>border-style:solid;</code>

      So the entire CSS should be:

      <code>
      <pre>
      .speech-bubble:after {
      content: “”;
      position: absolute;
      top: 100%;
      left: 20px;
      border-top: 20px outset black;
      border-top-color: inherit;
      border-left: 20px solid transparent;
      border-right: 20px solid transparent;
      }
      </pre>
      </code>

  18. Permalink to comment#

    A very creative use of CSS. To be honest, took me a bit to figure out the deal with the different borders.

  19. The problem i’m having is trying to get this to work on a horizontal list of elements. If i do the the :after on a list item then do left:20px; like you have above its positions the arrow 20px from teh left edge of the whole list, not that list item..

    
    
    .navbar .nav > li.active:after {
        content: "";
        width: 0;
        height: 0;
        border-top: 8px solid #58807e;
        border-left: 8px solid transparent;
        border-right: 8px solid transparent;
         position: absolute;
         top: 75%;
    left: 10px;
      
     }
    
    
    • Stephen Marx
      Permalink to comment#

      @Keith Mancuso: Make sure you have position:relative on your li.active element.

  20. Abhilash Verma

    What if I want the background to be a linear gradient?

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".