Hacker News new | comments | show | ask | jobs | submit login
CSS arrow please (cssarrowplease.com)
515 points by jimsteinhart on May 9, 2012 | hide | past | web | favorite | 73 comments

I've also just converted to LessCSS mixin. Free for your use. (I added a 6th argument so that you can change the class name that gets generated).

Clickable: https://gist.github.com/2644661

    .arrowgasm(@position: top, @size : "4px", @background-color :  #88b7d5, 
       @border-width: "2px", @border-color : #c2e1f5, @arrowClass : "arrow_box"){
         (~".@{arrowClass}") {
            position: relative;
            background: @background-color;
            border: @size solid @border-color;
        (~".@{arrowClass}:after"), (~".@{arrowClass}:before") {
                bottom: 100%;
                border: solid transparent;
                content: " ";
                height: 0;
                width: 0;
                position: absolute;
                pointer-events: none;

        (~".@{arrowClass}:after") {
                .b(@position, @background-color);
                border-width: @size;
                left: 50%;
                margin-left: @size * -1;
        (~".@{arrowClass}:before") {
               .b(@position, @border-color);
                border-width: @size + @border-width ;
                left: 50%;
                margin-left: ( @size + @border-width ) * -1;
        .b(top, @border-color)   { border-bottom-color: @border-color; }
        .b(right, @border-color) { border-left-color: @border-color;   }
        .b(bottom, @border-color){ border-top-color: @border-color;    }
        .b(left, @border-color)  { border-right-color: @border-color; }

You might also want to consider explicitly setting the box-sizing to content-box. I know that is the default, but if someone attempted to use this and had already adjusted the box-sizing to something else it would not work.

There are dozens of rules someone could already have on the page that would break it, why make a special case for box-sizing?

Because it's not unheard of to set * { box-sizing: border-box; }. In the same way, you shouldn't assume margin, padding or font-size to be anything in particular.

For those who enjoy sass:

    =triangle($direction: up, $size: 10px, $color: #000)
      width: 0
      height: 0
      @if $direction == up
        border-left: $size solid transparent
        border-right: $size solid transparent
        border-bottom: $size solid $color
      @else if $direction == down
        border-left: $size solid transparent
        border-right: $size solid transparent
        border-top: $size solid $color
      @else if $direction == left
        border-top: $size solid transparent
        border-bottom: $size solid transparent
        border-right: $size solid $color
      @else if $direction == right
        border-top: $size solid transparent
        border-bottom: $size solid transparent
        border-left: $size solid $color

I normally use SCSS, but this should work as well.

    =triangle($direction: top, $size: 10px, $color: #000)
      width: 0
      height: 0
      border: $size solid transparent
      border-#{$dir}-color: $color

css, sass and scss rocks. all those ideas should have their place in css3 or later.

Check out stylus, it's pretty neat too: http://learnboost.github.com/stylus/docs/js.html

My favorite features:

- auto-insert vendor prefixes, even IE filters (no need for css3 'mixins', which are most of the mixins the avg dev will need)

- can even rasterize linear-gradient backgrounds and serve as image for more pre-css3 browser support. This one I haven't tested but it sounds awesome

Edit: paragraph formatting

Yeah I actually prefer stylus to sass personally, sass is just more popular (and rails default) and less magical for people that don't work with css as often.

My favorite feature actually is that it can grab properties out of parents, as demonstrated here: https://gist.github.com/2563746

While that's cool, it's not quite what the OP achieves. Using this mixin will turn whatever you apply it to into a solid-color triangle with the passed-in options. The triangle will need to be its own element.

OP adds two triangles to whatever it is applied to, one for the border color, another to cover it up with the background color. And it doesn't require any additional elements... it just adds these to whatever you are applying it to.

You're totally right. I have a mixin that makes a bubble like that too, but it's built from a few different mixins that each build on each other and I didn't want to post a buttload of code in a comment. You can see an example of how mine looks if you hit this page (http://roots.carrotbeta.com/docs/) and scroll down to the UI section

That's a pretty groovy framework, thanks for sharing. Nice work.

thanks! it's closed and not yet public right now because the docs aren't finished yet - but this is how they look. I plan to have every section be live customizable and reflect implementation with a live code example to the left as is the case with the typography section. once the docs are done I'm planning on open sourcing it. If you want to use it and/or test it out, hit me on twitter @jescalan

I love the creativity that results from CSS' limitations (or, arguably, its flexibility). Neat trick.

It took me a moment to realize exactly what was going on to make this work. For those interested: borders are styled in such a way that they angle toward the edges if the border is large enough:

  \ /
  / \
That gives you four "V"s to work with. Therefore, to create the arrow, you simply need to hide all but the appropriate border. The border around the arrow is accomplished by underlaying another "V".

I still don't get it. What do you mean that "borders are styled in such a way that they angle toward the edges if the border is large enough"? What causes the angle?

Thanks, I had no clue how this trick worked until I saw your link.

Awesome~ Thank you for posting this link. I had understood the use of wide solid borders with a 0 height and width div, but how the angle was being achieved was perplexing. I was imagining borders as solid rectangles that overlap each other at the corners. This has been a revelation! I have discovered an awesome new power. Thanks!

Another thanks! I was scratching my head for a while.

thanks, that's a much better explanation

growt's link does an excellent job of illustrating it.

Ultimately, how the border is joined at the corners is undefined by the specification:

> Note: This specification does not define how borders of different styles should be joined in the corner. [...]

Many rendering engines will join borders at an angle, producing those diagonal lines.

This is the way to do it, until the graphics guy wants the box to have a drop shadow. The pseudo elements' shadow is square, so your options are either to hope that nobody notices that the arrow doesn't have a shadow (like in this example), or to use an image for the arrow.

Here's a quick hack for a CSS arrow that casts a shadow. http://jsfiddle.net/BKtnn/1/

Adding border is a bit problematic but I'm sure solution could be found, just a question of few more minutes. Also, it should be doable in IE with filters.

That looks surprisingly good for me in Firefox, but from my experiments making these tricks work in production, browser standardization is a long way from the point where we can do this at arbitrary sizes in the real world.

The problem, more than anything, is the way these css-only triangles get aliased. Since they're a side-effect of rendering borders, they never get properly anti-aliased the way fonts and shape edges do, and as a result the edges end up jagged at certain sizes and color combinations.

This solution doesn't work. This has a overlapping shadow issue right around where the arrow pops out of the box. It doesn't look as obvious on that tiny shadow you have, on wider shadows it is glaringly obvious and looks terrible.

Yes, the designer in this project naturally wanted both a border and a box shadow. I don't know how to accomplish that in CSS without using additional elements. I'm currently using strategy #1, hoping that nobody notices :)

As in the elsewhere linked CSS Hexagon tutorial (see last comment on http://jtauber.github.com/articles/css-hexagon.html) it's noted that there's a hexagon character. Well there are also triangle characters - which you could apply a [or multiple] shadow[s] to.

The gathered troops here were all cooing at this demo until the drop shadow was noticed as absent from the arrow. A real shame (although obviously the box-shadow being bounded by the rectangle makes it impossible to do this way).

Maybe it's time to propose a mask-shadow property?

This made me to the sky and back to hell in one second.

I need to do exactly this in a google maps infobox, BUT with the dawn shadow... :( back to images I guess.

This sort of thing used to happen a lot at an Android app company I worked for. It would be easier and cleaner to implement something like a button background in XML, but it wouldn't look nearly as good as a button produced using real graphics. It wasn't just looks either, they were less usable in that case. If a button doesn't look 3D due to being limited to a simple linear gradient or something then users are less likely to click it, and we did have user testing reports of people mistaking the biggest buttons that we wanted people to click most for section titles. So even if a shadow can be pulled off, what else is missing that a raster graphics solution would include. ;/

You know, not having a shadow on the Arrow (if arrow is on bottom) kind looks like it's popping off the page then, at a slight angle. I don't mind it - tho obviously not for every use.

Here's a method I use for getting box-shadows on the arrow http://tinkerbin.com/cRhPGwmh

Thanks, but I cannot see the shadow in it.

I really suck at CSS. I mean, I really suck. It takes me forever to accomplish the smallest things. I love these sites that keep popping up that generate CSS for cool little effects.


This and other utility and howto sites are very helpful, agreed.

BTW, to hone your CSS skills, try dropping into Firebug or Chrome's developer tools and just playing around -- very easy way to learn and get CSS stuff done. The CSS panel lets you change rules and values and see the effects immediately. I know in Chrome I use the up/down arrows on a value to slide objects and spacing around on the screen regularly. The panel also helps greatly in understanding cascading; see also the "computed styles" section.

Yup, I suck at CSS too. I still think there's something fundamentally wrong with it, but that's probably more a marker on my own ignorance than anything.

Anyway, I do have fun playing around with the FF style tools. It is quite cool and informative.

CSS was clearly designed with typography and text layout in mind - and it works wonderfully for that purpose. But it was not created flexibly enough to be well suited for anything else. You CAN make graphical interfaces with it (and we do, because we have to). But it's all hacks.

I think the browser inconsistencies are as frustrating as they are because doing seemingly "simple" things in CSS requires using advanced CSS features in boundary-pushing ways (this wonderful arrow box app is a perfect example). Browser support has to be EXCELLENT before certain simple layout things are even possible. Imagine a CSS that supported things like "vertical-align: center". That's a CSS that wouldn't NEED to have its boundaries pushed to the limits and the rough edges of browsers wouldn't rankle nearly so much.

It never ceases to amaze me how quickly people jump to defend CSS as if any criticisms imply that the author thinks we'd be better off back in the days of deeply nested tables. But the sad fact of the matter is that some things really were easier and more dependable (and in some cases, WAY more so) with tables.

> It never ceases to amaze me how quickly people jump to defend CSS as if any criticisms imply that the author thinks we'd be better off back in the days of deeply nested tables.

Could not agree more. Tech people are weird sometimes.

The same thing repeats itself in other contexts; for example people hate to hear criticism of git, because to many people it is the be-all-end-all of version control. But just because it's better than what came before doesn't mean there's not room to improve it even further.

Late reply, but that's how I feel somewhat. I feel like CSS isn't intuitive at all for an application layout. I've done layouts in other markup languages and had a blast, but when I hit HTML and CSS, I just feel generally confused. Again, I hardly ever do web design, so it could just be ignorance on my part, but I still feel CSS could use a makeover instead of incremental changes.

I personally don't have an issue with CSS. The issue for me is the inconsistent implementations across browsers. That has been my real pain point, and it continues to keep me away from really learning CSS.

It just seems like there could be a simpler system to me. (Simpler in terms of properties and such, as opposed to syntax. Also, variables and stuff in CSS would be nice obviously). But I agree, inconsistency is always frustrating.

This is great so long as you don't still have to support IE7.


In IE7 you'd just have a box without the triangle, no? Isn't that graceful degradation?

Nope, you don't have a box at all (at least on this webpage). Nor the left-side box.

It looks awful on IE7 actually, the footer also degrades un-gracefully.

I wrote this a while ago, using some actual HTML elements—to get it to work super cross-browser: http://mrcoles.com/blog/callout-box-css-border-triangles-cro...

IE8 as well.

That's so funny... just yesterday I built my own sass mixin to create custom triangles to do the little arrow pointer on a dialog box like this. Two triangles (border color and background color) with an offset. I toyed with using :before and/or :after to create the second background-color triangle, but the specs said you could only do text or an image so I didn't even try to make the triangle. My version required something like <div class="arrow arrow-left"><div class="arrow-inner arrow-inner-left"></div></div>. This is so much more semantic, elegant, and awesome. I love it!

I would not call this _more semantic_.

It is definitely a very cool and clean hack (more of these on HN, please), but not semantic at all: in the source there is not indication that the box is pointing at something or where it is pointing.

Looking at the domain name I thought it was a public request for a new CSS property like

  p {
      border-bottom-right-cap: solid-arrow-outward;

I think it's more semantic than a non-content div or image that has no real semantic content, which is what my solution (and most I've seen) amounted to. I suppose ideally some property on the dialog container like 'data-refersto="#indicatedContent"' would be a little more semantic. And eventually that could be implemented directly in HTML and stylable in CSS. That'd be neat.

This needs 2 easy additions, a slider to move the arrow closer to either corner of the edge it's on and a slider to change how big the arrow is.

I made a bunch of this kind (and more complex) speech bubbles a couple of years ago: http://nicolasgallagher.com/pure-css-speech-bubbles/demo/

This is a nice little tool to help automate the production of the code for simple ones.

Because the shadow seems to be setup so that the light source is at the top, when you move the arrow to any other position, the lack of shadow under the arrow becomes noticeable.

If the light source moved along with the triangle, no shadow under the arrow would be required (imo).

Has a small line running through the arrow on safari (mobile). FYR

That's probably because the CSS pixel resolution isn't matching the device/screen resolution so you're seeing the edge of two elements that don't quite match (imagine a percentage being rounded). If the page included a meta viewport tag with the correct default zoom level there would probably be no line (not tested) until you zoomed in or out.

I've been writing CSS for a couple of years now and it took me like 10 minutes to understand why this is even working.

I already feel sorry for anyone that will be debugging this mess.

The harder thing is getting the boxshadow to work on that.

I posted a Sass mixin for doing this here: https://gist.github.com/2645575

Browser support? Any idea if this works in IE7/8?

No IE7/8 support because it doesn't do CSS generated content or the :before and :after pseudo-elements.

Arrow is repeated too many times nowadays. Neat.

I was going to use an CSS tool today, but, then i took an arrow to the knee.

The demo page is broken in IE8, although it does work when you copy the HTML/CSS to a new file.

The demo page is broken in IE8

I prefer to say that “IE8 is broken when attempting to render the demo page,” but either way, good catch.

waste of a domain name, why do people create a whole new domain name for something as simple as this, this could have easily been a blog post! (IMO)

Not that I have anything to do with it, but two issues come to mind immediately: it may be easier to get organic search traffic for the idea, and it is a good way of keeping projects nice and separate.

Brilliant, I have a use case for this, nice timing :-)

Thank you sir! This might come in handy sometimes.

Loved the tool !!


May I request that the arrow has a drop shadow too. I mean this is not exactly rocket science, but the drop shadow will be much tougher.

wrap it up in a cocoa app please, so I can use it when I'm not online.

File -> Save Page As?

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact