As I’m sure most designers who also like to code already have the hang of this, I still want to put it down in writing for those of you who still aren’t familiar with what tricks you can use in CSS to get your way around. I’ve often found myself needing to insert different triangle/arrow shapes in my designs and had to find the best and most flexible way of doing this. You can see these tiny bits of UI in loads of designs, from comment bubles and tooltips to dropdown menus and active menu items. Yeah, they’re all over the place. So how can it be done?

css-triangles-dropdowns
css-triangles-comments
css-triangles-tooltip

Image sprites

This is the most obvious method I can think of, just place your image in a transparent PNG sprite and add it as a background for you shape container in CSS. Should you use it? Well… yes and no. It might be good for backwards browser compatibility but that’s basically it, it’s not scalable, it’s a hassle to readjust and tweak and it’s not pixel sharp.

css-triangles-sprite

Web-fonts

It’s somewhat similar to the previous solution, only that you use a web-font’s glyphs to output the triangles. Now this can be easier if you’re already using a web-font in your project and if it has the glyphs already included. If not, then you’re going to have to create those glyphs on your own, add them to the font, map them and everything else.

Also, while it’s infinitely scalable compared to the image sprite, you will still end up with some font files on your server as well as the extra lines of CSS needed to assign each glyph to a class. So it’s not the most elegant solution, but it’s a solution nonetheless. However, what if we could accomplish this with just CSS? Pixel sharp edges, simple CSS code and no extra server requests?

CSS borders

By far the best way of accomplishing this, in my opinion, is using a container – div – and splitting it up into triangles. We can do this quite easily by applying CSS borders on the size-less container and giving these borders a solid style with a height corresponding to the size we want our final triangle to be. We can also combine two consecutive borders in order to obtain larger triangles facing sideways (instead of centered):

.four-triangles {
    width: 0;
    height: 0;
    content: '';
    border-width: 50px;
    border-style: solid;
    border-color: #C6E8A2 #A2C5E8 #DDDDDD #E8A2A2;
}
.two-triangles {
    width: 0;
    height: 0;
    content: '';
    border-width: 50px;
    border-style: solid;
    border-color: #C6E8A2 #C6E8A2 #E8A2A2 #E8A2A2;
}

So now that we have our square split up into triangles, we might want to keep just one of them. Considering that it’s made out of borders, we can solve this easily by making the ones we don’t need transparent and to get an arrow pointing in one direction, we just apply an opaque color to the border on the opposite side. For example, to get an arrow pointing right, we just leave every border transparent except for the one on the left and so on:

.arrow-left {
    width: 0;
    height: 0;
    content: '';
    border-width: 50px;
    border-style: solid;
    border-color: transparent #ddd transparent transparent;
}
.arrow-right {
    width: 0;
    height: 0;
    content: '';
    border-width: 50px;
    border-style: solid;
    border-color: transparent transparent transparent #ddd;
}
 
.arrow-down {
    width: 0;
    height: 0;
    content: '';
    border-width: 50px;
    border-style: solid;
    border-color: #ddd transparent transparent transparent;
}
 
.arrow-up {
    width: 0;
    height: 0;
    content: '';
    border-width: 50px;
    border-style: solid;
    border-color: transparent transparent #ddd transparent;
}

So basically by playing aroung with the colors for each of the borders – top, right, bottom, left – we can achieve some pretty efficient results in terms of shape rendering, results which can be used in combinations with other blocks of content (as I’ve said: comment bubbles, dropdown menus etc.) To add such a triangle to an already existent container we’ll just use the very helpful :before and :after pseudo-elements which are compatible with all major browsers.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.
.comment {
    position: relative;
    width: 100%;
    border-radius: 5px;
    background: #eee;
    color: #999;
    font-style: italic;
    padding: 20px;
}
.comment:before {
    position: absolute;
    top: 100%;
    left: 20px;
    width: 0;
    height: 0;
    content: '';
    border-width: 12px;
    border-style: solid;
    border-color: #eee transparent transparent transparent;
}

And by using both pseudo-elements in the same time, but with different border colors we can create an outline that follows the container and then “moves” onto it’s arrow:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet.
.comment-outline {
    position: relative;
    width: 100%;
    border-radius: 5px;
    background: #f5f5f5;
    border: 1px solid #ccc;
    color: #999;
    font-style: italic;
    padding: 20px;
}
.comment-outline:before {
    position: absolute;
    top: 100%;
    left: 20px;
    width: 0;
    height: 0;
    content: '';
    border-width: 12px;
    border-style: solid;
    border-color: #ccc transparent transparent transparent;
}
.comment-outline:after {
    position: absolute;
    top: 100%;
    left: 20px;
    margin-top: -1px;
    width: 0;
    height: 0;
    content: '';
    border-width: 12px;
    border-style: solid;
    border-color: #f5f5f5 transparent transparent transparent;
}

So in the end we have a very simple solution for a very frequent issue, that is fast, completely scalable, pixel sharp, Javascript free and simple to readjust whenever needed, all without loading extra files in your page and sending more requests to the server. If it’s hard for you write the code every time you need a triangle, just use this online CSS generator and save time (at least until you get the hand of it to write the code on your own).

Leave a comment