Interesting question:
css3 speech bubble question: for the “triangle”‘s border color, how can I set it to whatever its parent div’s bgcolor is automagically?
— Jin Yang (@jzy) February 1, 2012
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.
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.
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.
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 */
}
Forgive my typos…
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:
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…
Hey Chris! I believe this explains why you can’t inherit from shorthand properties: http://www.w3.org/TR/2002/WD-CSS21-20020802/changes.html#q3
Indeed. Makes sense.
You can use this JavaScript library http://ie7-js.googlecode.com/ to enable support for pseudo elements in IE 6, 7, among many other modern browsers features, listed here http://ie7-js.googlecode.com/svn/test/index.html
I’m impressed with the verbiage – “I like bananas, because they have no bones.” Thanks for the laugh!
Comes handy also in normal usage. Thanks!
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)?
Wouldn’t it be nice if this worked:
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 adata-background
attribute. Just get the background-color value:Am I wrong?
It can be done by pure CSS in future, but not now.
http://dev.w3.org/csswg/css-variables/
Or if you’re using SCSS or a comparable extension, you can do it now.
Great tip, thanks Chris.
By the way, love ShopTalk!
.speech-bubble – shouldn’t it have a line “position: relative;”?
Very userful tip.
Thanks!
Hi, Chris. There is a reduced version of the second css rule:
Thanks for sharing this fresh idea.
May be wikll be possible and with ‘currentColor’ ? :P)
“I like bananas, because they have no bones.” from the man himself… Mr Robyn Hitchcock!
sorry, only a test of your great form
Excellent article, thanks a learn some amazing tricks.
tnx Chris, this is exactly what i was looking for :)
I didn’t quite understand which part of the code is responsible for the triangle thingy… Is it the “transparent” keyword?
please can you Chris let us know how this trialing created
i cant see where did you created in your code !!
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’;”
… 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>
A very creative use of CSS. To be honest, took me a bit to figure out the deal with the different borders.
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..
@Keith Mancuso: Make sure you have position:relative on your li.active element.
What if I want the background to be a linear gradient?