Grow your CSS skills. Land your dream job.

Triangle With Shadow

Published by Chris Coyier

You probably already know you can make triangles with CSS. But what if you want to put a shadow behind it? Unfortunately the classic border trick doesn't change the shape of the element, it's just a visual trick. Let's look at a couple alternative solutions.

Just use Unicode

There are triangle characters in unicode. Like:

▲▼◀▶

And way more.

If you use that as your triangle, you can select it and do all kinds of fancy to it.

<span class="triangle">▲</span>
.triangle {
   color: #BADA55;
   text-shadow: 0 0 20px black;
}

Color, shadows, sizing, whatever. You could even get more fancy. If the triangle isn't the exact shape you want or doesn't point the right way, you can use CSS3 transform stuff to stretch it or rotate it. Here's a demo like that:

I like this technique, but there are some obvious issues. One is that relying on CSS3 transform features doesn't get you very deep browser support. Certainly no IE 8. But hey, this article is about shadows, so that's CSS3 anyway. Even Older browsers than that may have trouble with the unicode icons themselves. So fair warning.

The Double-Box Method

Assuming we're cool with CSS3, one method would be to have a container box with hidden overflow and another box inside it which is rotate and hangs out of it. The part that is still visible would form a triangle. Then you can use a box-shadow on both the boxes to achieve a shadow all the way around.

<div class="triangle-with-shadow"></div>
.triangle-with-shadow {
   width: 100px;
   height: 100px;
   position: relative;
   overflow: hidden;
   box-shadow: 0 16px 10px -17px rgba(0,0,0,0.5);
}
.triangle-with-shadow:after {
   content: "";
   position: absolute;
   width: 50px;
   height: 50px;
   background: #999;
   transform: rotate(45deg); /* Prefixes... */
   top: 75px;
   left: 25px;
   box-shadow: -1px -1px 10px -2px rgba(0,0,0,0.5);
}

Notice we use negative spread radius on the parent in which to get the shadow to only come off of one side. Here's a demo like that:

Just use an image

I'm not a big fan of this, because it's an extra HTTP Request or another thing to manage in your sprite. And you'll have the "responsive images" (won't look as nice on pixel dense displays unless you have multiple versions of it ready for that and go to great lengths to fix). The other techniques are essentially drawn with vector so will be sharp in any environment.

But, you know, nobody will die and you'll get good browser support.

The Future

You'll be able to use filter: drop-shadow() to cast a shadow over the shape very easily. Here's an article about it.

Comments

  1. Jon
    Permalink to comment#

    As usual you continue to amaze.

  2. Permalink to comment#

    Anyone else saddened by how much of a hack it is to get any non-rectangular shape in html even at this point? A triangle. You know, the kind of stuff that the greeks had a great handle on? a^2 + b^2 = c^2 ?

    And don’t even get me started on circles.

  3. Are there any browser or OS compatibility issues with using unicode characters?

    Using unicode seems even simpler than using borders to make a triangle. Plus the benefit of being able to use text-shadow! I like it.

    • Permalink to comment#

      Seems that IE8 doesn’t like unicode. It fails the Modernizr test, but at least you can use a fallback in that case.

    • Flimm
      Permalink to comment#

      Te get a weird Unicode character to display correctly, the user needs to have an appropriate font installed, a font which supports that character.

      I suppose you could use web-fonts to get around that issue, but at that point, why not use a symbol font?

  4. So turns out that #BADA55 color is not an actual badass… So disappointed to see this :(

  5. If a border would be enough you one can always do something like this:
    Pure CSS arrow with border (tooltip)

  6. Nate
    Permalink to comment#

    Canvas version of the same thing.

    http://jsfiddle.net/SdeeV/

  7. I like the font solution but why not avoid the Unicode issues and go for a symbol font using @font-face? That way most browsers provide support and you get to keep the triangle even if it doesn’t always have a shadow.

  8. how about placing :
    transition: all 0.2s ease;
    in the span selector, to make it more smooth when hovering the triangle.

  9. Justin
    Permalink to comment#

    Am I the only one that is bothered by how the Unicode triangles are not the exact same shape rotated 4 different ways, but 4 different triangles slightly different in size and dimension? It’s most noticable with the right/left triangles — the right-pointing one is slightly shorter than the left-pointing one. That just erks me like crazy!

  10. Permalink to comment#

    Nice. I am totally amazed to see the solution. But i am curious is it possible to create other icon or shapes using something same. If possible can anybody share the URL?

  11. Permalink to comment#

    color: #BADA55 ha ha ha ha. Nice one. On the topic though, we have created two custom fonts and used font squirrel to generate the different versions. This has saved us a lot of frustration when changing colour on hover, even just transition effects became much easier to deal with.

    Sinan

    • I love this idea. Any recommendations on font tools?

    • Permalink to comment#

      Hey Steve,
      first we used illustrator to prepare all the characters “icons” we wanted, then we used http://www.fontlab.com/ to create the font, and finally http://www.fontsquirrel.com/ to convert our font using their font generator.

      You can use any other font creation software of course. This was an Idea I had after so many times the design and layout changes for a project after being launched. At one point the site changed colour scheme! So you can imagine how daunting of a task to go back and edit your sprites. With this now it’s simple :)

      .social {
      color: #900;
      font-size: 30;
      }

      You don’t like that?

      .social {
      color: #ddd;
      font-size: 20;
      test-shadow: 3px 3px 2px rgba(0,0,0,.3);
      }

      More like it?

      :)

  12. wow…..amazing Effect . I will try it in my blog.

  13. An SVG would look good at any pixel density.

    • True that, but then you are making an extra http request to get that file. Not the end of the world, but something to think about. You’d have to add the drop shadow in the SVG graphic itself as well. Maybe not a bad thing depending on your use, but it may be difficult to match the shadow to other CSS-generated shadows.

      I used a bunch of CSS arrows in a recent project and I loved that I could change the color and orientation of these arrows without having to make a bunch of different asset files. Again, little things, but I love the little details.

    • DED
      Permalink to comment#

      SVG isn’t a separate download, it is drawn into the HTML as a child element. As such it becomes part of the DOM and can be styled with CSS like any other element in the page. So you can match the colors with other CSS styled elements. With a library such as Raphael or D3, the job is easier and has backup for older browsers.

    • I suppose that’s true depending on how you’re using the SVG assets. While Raphael is great for this kinda thing, it maybe overkill to pull in a whole library for an arrow or two. Don’t get me wrong, I love using SVG. But in my opinion, you need to use a quite a few of them to justify loading another JS library. I think that’s why there is such a demand to try and pull off these effect in CSS.

  14. Permalink to comment#

    I was surprised to see this blog post on My Linked In Today news reel. As always great post!

  15. Jason
    Permalink to comment#

    Wouldn’t it make sense to use Base64 Encoding for images as small as a monochromatic triangle? I made a simple triangle PNG, ran it through my PNG optimizers, and got the encoding down to around 200 characters, which seems very reasonable to me.

  16. Krinkle
    Permalink to comment#

    @Josh Johnson, @Jason, @Steve Schrab: Haven’t thought it through completely, but what about the best of both worlds?

    Embed the SVG in your stylesheet (since it isn’t binary, it wouldn’t have to be base64 encoded either). I know that IE (at least older versions of IE), only support data URI embedding for “images” so not sure if that includes SVG, but as a future idea… embedding an SVG in a stylesheets – sounds pretty cool!

    The advantage over a PNG is that SVG is resolution independent and is also much easier to maintain (no need to keep a PNG file around that is periodically re-encoded/re-embedded, one could maintain the SVG right in the stylesheet!).

    The advantage over a Unicode character (either in a CSS “content” property or as the text content of an actual DOM element) is that the SVG shape is completely flexible, not dependent on any fonts and has a reliable interpretation by all browsers . Reliable how? Well, most fonts don’t implement all the Unicode characters, meaning, in most cases the font will fall back for those characters to a system default font that does implement those characters. However the problem there is that different OS/browsers have different default fonts. And different fonts implement those characters in slightly different ways.
    I ran into this when I was using “⟨” (U+27E8) as an arrow on a button in a javascript slider. I liked the shape a lot, and gave me the freedom of animating the text color, size and what not. But relying on the height and spacing of it turned out to be a problem when I find out on most Windows systems the arrow looked very different than on my trusted Mac. The arrow was wider and shorter, totally unusable in the design I had, bummer. Temporarily fixed by using a transparent PNG instead (exported by typing the character in Photoshop). As an aside, one advantage I got when I switched to PNG was the ability to easily center align it vertically regardless of padding (text can do this too using line-height, but less flexible).

    The advantage over the double-box method is that with an SVG embedded background image you keep the stylesheet a lot cleaner and easier to read, and maybe also cheaper to render, saves you an “:after” (that can then be used for something else) and less fragile by not depending on how browsers render the box model in these “edge” cases (such as border-radius “bug” (if it even is a bug) where Safari used to treat radiuses larger than the box itself differently than Firefox).

    The only downside I can think of is compatibility with older browsers and flexibility in variation (e.g. inherit from a css class and making it a different color isn’t as easy, might require duplicating the SVG multiple times, whereas with the double-box method one could use a shared class and create an suplemental class that only overrides some properties).

    Although using an (embedded SVG) background also gives some interesting abilities. Such as using background-position (center center?) and background-size (imagine using “background-size: cover” for an embedded SVG background, and have it scale automatically over the entire size of an element).

    Just some random (untested) ideas,
    – Krinkle

    • Krinkle
      Permalink to comment#

      Of course, by using a background you can’t use css to style/animate the actual SVG object. But as DED mentioned earlier, one could embed the SVG inside the HTML as well. No need for a library of some sorts.

  17. mike@c572.caht I’d point out that on my shiny new android tablet, I see 4 boxes there. Seems there’s no arrows in the font. That might be an argument for combining this with @font-face when possible.

  18. Launcher Go
    Permalink to comment#

    This is great but I still hope w3c can make this stuff more easier~

  19. Permalink to comment#

    I already used this technique and heres a pro-tip. To have the triangle perfectly aligned you have to reset font-size and pick a font face really carefully. Rendering will differ between platforms.

  20. hey …
    as always u have done a great job..
    i learned a lot from your post …
    Thanks a lot…

  21. all good in the hood, but isn’t extra markup ugly, just to show a triangle? i use :after-triangle to show some active state.

  22. Gotta say that you continue to come up with some very intriguing ideas, it’s a pity that there isn’t a easier way of doing things like this. No doubt there will be at some point but until then, we gotta make do I guess.

  23. I have also made CSS3 triangles with borders & shadows, you can check out my post on forrst.

    http://forrst.com/posts/CSS3_Triangle_Gradients-XGU

  24. If you don’t have to support older browsers you can use the border trick to create triangles and still add box-shadow to it.

    You just have to make two adjoining sides of the border non-transparent instead of one and rotate the whole thing by 45deg.
    Then you can add proper box-shadow to the triangle as i’ve shown in this example:

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".