I have a project where I need to insert speech bubbles / message boxes. The general shape I am trying to achieve is this one :
.bubble {
height: 100px;
width: 200px;
border: 3px solid gray;
background: lightgray;
position: relative;
cursor:pointer;
}
.triangle {
width: 0;
border-top: 20px solid black;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
cursor:pointer;
}
<div class="bubble">Speech bubble
</div>
<div class="triangle">
</div>
This currently does not pass a hit-test as the transparent border is also clickable.
Objectives
The hit box (clickable / hoverable areas) needs to stick to the shape's boundaries (the transparent borders here are also hoverable, invalidating this).
I need to display the shape over various content (images, gradents, text...),
Issues
The main issues I am having when manipulating this shape are:
- Have the ability to move the triangle around the speech bubble according to the position of the element it refers to (top/left/right/bottom sides)
- adding a border or box shadow around it when emphasis is needed
Is there anyway of addressing these issues?
I have found this wonderful service for making customizable CSS arrows. Just generate it and use with any block.
http://www.cssarrowplease.com/
In order to achieve this, you should consider altering your markup in order to make your html more efficient. This can be achieved using a pseudo element. I'll address each point individually, and put it all together at the end of my answer.
First of all,
Use pseudo elements to avoid extra elements
You could use a pseudo element to remove the extra
.triangle
div. This not only reduces your div numbers, but also helps with positioning as you can use thetop:
left:
right:
andbottom:
css properties in order to position according to your main element. This can be seen below:Hit testing
In order to create your "hit test", you may wish to use a rotated element instead of a border hack.
Something like:
or use a skewed pseudo element:
which will show the pointer only when the square or main element is hovered. But hang on, that messes up the positioning? how can you deal with that?
There are a few solutions to that. One of which is to use the
calc
CSS property.Adding a border
You can add a border quite easily now, simply by adding a border declaration to the main element, and setting the
border-bottom
andborder-right
of the pseudo element toinherit
Border
Box Shadow:
In order to have a box shadow, I've used the
:after
pseudo element in order to hide the box shadow over the other pseudo, making the element seem as one single element.Putting it all together
You can also add a border radius to your message box or speech bubble by again, using the border-radius property:
This even allows you to create not only a triangle, but how about a circle instead?
If you are having issues with content overflowing and being 'hidden' behind this pseudo element, and you aren't fussed about having a border, you could use a negative z-index which will solve this issue.
Don't like using 'magic numbers'?
If you don't like the idea of using a calc value, in which the positioning in my answer is currently using (whilst working), you may wish to use
transform:translate(50%)
This would be a much better approach, since:
Want to move it? You can!
Want it one the right?
Want it to be a different shape of triangle?
SVG
This can be done using the pointer-events in svg.
pointer-events:visibleFill;
Will only select the part where there is paint.This example uses filter_box-shadow and is not supported by IE.
Also uses two shapes.
This example uses one path
Should be fully supported by IE.