Creating arrows with CSS

February 24 2012

Ever have a button, navigation option, or other element, that has an expandable menu that needs some kind of designator that the option has more to offer?

In the days of old, the most common method to make this happen was to create an image that has a down arrow built into the image. With the advent of CSS3, the gradients, curved borders and other options are under control — but what about that arrow. Lurking in the shadows is a method that can create this arrow in solid CSS that is functional even in IE7.

Now that I have your attention, let us get to the nitty gritty details. I first came across this technique when creating expanding menus in responsive design. With limited screen size, I could hide menu options under a menu button, exposing the options only when the user wants to see them. However, I needed a way to let people know that there was 'more' under the button. The old way of thinking was to instantly go looking for an image that you would set on the background of an element and use background-positioned to place the image where I needed. Combined with some padding within the element, my logic was not flawed — just outdated.

So where did I go? Google naturally, in search of a royalty-free image! It was on that I noticed that even Google uses this technique to indicate an option for more. If you visit and look across the top menu options, you will find a 'more' option with the exact type of image I was looking for. Of course, being a front-end web developer, I naturally decided to 'Inspect Element' and take a look at the generated code; I wanted to acquire an idea for the size of the image being use. And low and behold, what did I find? No image at all! Needless to say, my interest was peaked. On closer evaluation, I found the technique that I will now breakdown into clear terms that anyone can understand. Well I say anyone, but I am sure my 7 month old daughter would just smile and coo at me

HTML Mark-up

We will not get far in this without a tad-bit of HTML to base this article on.

<div id="container">
  <div class="vertical_facing_arrow"></div>
  <div class="horizontal_facing_arrow"></div>

HTML markup needed to make everything happen

CSS Mark-up

Now that we have an HTML structure to work with, we can now add some CSS that will power the entire show. Let's start with the down arrow as this will generally be the first display to expand an option.

.vertical_facing_arrow {
  border-color: #FFF transparent;
  border-style: solid;
  border-width: 10px 10px 0;
  display: inline-block;
  font-size: 0;
  height: 0;
  line-height: 0;
  width: 0;

CSS declarations that power CSS arrows

Understanding and Reasoning

I know what you are thinking; what's with all those zeros! Well let me tell you why they are there. The only part of this element that we are interested in is the borders on the element. It is the borders that are creating this visual arrow representation. Setting the font-size, height, line-height, and width of the element removes the content that would be in the field and allows for only the element's borders to thrive before your eyes. Truth be told, all you need to remove the text from the element is setting the font-size to 0. Setting the height, line-height, and width to 0 ensures that all browsers respect that we are only wanting the borders. So let's take a look at the other factors in this CSS declaration. There are two other key elements present here — borders and display. First, lets get the display out of the way and then dive into the core of the functionality. As many front-end developers already know, IE7 does not recognize inline-block as a display value. However, what I have found is that, for once, IE7 will place nicely with this clause in the CSS declaration. In the end, set display: inline-block and you can ensure that your display options are ready to roll. Finally, we round the corner to the main portion that makes all of the magic happen — the borders. As you can tell, I have taken a route of using the individual border clauses instead of the standard short-hand border clause. My reasoning for this is simple. Using the shorthand calls for 4 clauses declared and this route only calls for three. Simple and efficient. Now let's review the three clauses separately. border-color This is where you would control the color of the arrow you are creating. As you can tell, we are only setting the color on the top border and setting the other sides to transparent. What this does is allow for a tapering of the border into a perfect arrow. More on this below. border-style For the most part, people will be looking for a solid color arrow and thus, solid is going to be what we choose to use. However, experimenting with the other various values for border-style shows a myriad of different effects. Setting groove to the border-style create a nice two-tone effect to the arrow; setting ridge will reverse the color order of the two-tone effects on the arrow. Inset and outset are also opposites that will swap between the white and grey but these make for a solid color; best to just keep a solid color defined in this instance. border-width No borders are created equal — that is unless defined that way   However, changing the order and numbers have various different affects. In the example, we defined 10 pixels for the top, left, and right while keeping the bottom border set to 0. Now if you reference the color clauses above, you will notice that the left and right colors are transparent. So what you can imagine is a square with a center point defined by an imaginary X in the square. Here is a visual for you  

Notice how there are four quadrants of this square. Now envision the coloring effects as defined above. Starting to make sense yet? I bet it is. The bottom triangle is set to 0, therefore not displaying at all. The left and right have a height set but are transparent. Now I know what some may be thinking; "why not just set the left and right to 0 as well". Well here is the deal there. We set the 10px to the top border and this sets the height of the border/arrow and naturally, the 10px defined to the left and right define the width of the entire element; they are needed to have a height and width for the two-dimensional effect. Now do you really want to add some nice effects to this when being used, you can either use JavaScript to change out classes, or just change the CSS completely for that matter, or add a few changes to the :hover state. With a down facing arrow that shows that the option can expand, it is natural to want to have an upwards facing arrow arrow when the element is expanded; thus, indicating that the element can then contact. For the purposes of this explanation, we will just use the hover style in CSS. So let's show some CSS

.vertical_facing_arrow:hover {
  border-color: transparent transparent #FFF;
  border-width: 0 10px 10px;

As you can clearly tell, all we needed to do was change the positioning of the color and the width. Since we now want the border to begin at the bottom and not include the top, we change the clause to reflect this and, in essence, just swap them around. And guess what, the horzontal arrows work the same way. Just change the placement of the color and the width to force the arrow to point in the direction you desire; up, down, left or right. And in the end, we have perfectly styled vertical and horizontal facing arrows in solid CSS that can react to the environment that you have decided to use them in.