CSS Rounded Corners Menus

So, you want to make multiple valid cross-browser, rounded corner navigation buttons that are resizable, have a hover state, degrade gracefully, and use only CSS and one image? No problem.

I've looked at a few rounded corner solutions, but so far I haven't really found what I was looking for, so I decided to try working it out myself. I wanted a solution that was lightweight, valid, cross-browser, and didn't require JavaScript. The technique I came up with isn't the end all solution for rounded corners and I'm sure that I'm not the first to use it, but it did meet my needs, and so I'm satisfied with the result. The only caveat I'll make before we dive into the code is that I did end up needing a single line of JavaScript in order to make Internet Explorer 6 function properly without flickering. Let's get started.

Explaining CSS Positioning

If you're trying to figure out CSS positioning on your own, it can be a little confusing. I'm going to attempt to explain it briefly and clearly because a good understanding of positioning is vital to this tutorial. If you're able to master positioning, you'll be able to apply it to many other uses in your web design.

CSS Positioning Chart

There are five values that can be assigned to the CSS position property: absolute, fixed, inherit, relative, and static. Let's look at each of them in turn:

  • absolute — An element that has been absolutely-positioned will be taken out of the normal flow of the page. This means that the content around it will act like the absolutely-positioned element never existed. That element will instead be positioned according to its distance from the edges of the entire scrollable page.
  • fixed — When an element has been assigned position:fixed; it will be taken out of the normal flow of the page, similar to position:absolute. However, a fixed element will be positioned according to its distance from the edges of the viewable page and will stay in visibly in place even when the page is scrolled. It should be noted that Internet Explorer 6 does not support fixed positioning and that any fixed elements will scroll.
  • inherit — This value simply means that the element inherits the positioning set for its parent element.
  • relative — A relatively-positioned element will remain within the flow of the page, meaning that a placeholder the exact size of the element will mark its original place, even if that element has been positioned elsewhere. Any position changes are also relative to the element's original position and not the borders of the page or the viewing area.
  • static — The default positioning of all elements. Static elements remain in the normal page flow and do not move.

The absolute, fixed, and relative positions should be used in conjunction with the top, right, bottom, and left properties. Each of those properties can be given values in ems, pxs, or percentages as well as the values top, right, bottom, and left.

There is one additional nuance to positioning that is quite useful and indeed, it will be the key to this tutorial. If an absolutely-positioned element has a parent element that is relatively-positioned, the child element will instead be positioned according to the boundaries of its parent, rather than the boundaries of the page.

Now that we've briefly covered CSS positioning, let's tackle the example.

The (X)HTML

For the purposes of the tutorial, I'm only going to make a horizontal navigation menu with one type of button, but if you look at the source code for this page, you will see multiple buttons and boxes that all use the same image. We're going to make a generic menu, but feel free to spice it up if you like. The markup will validate for both strict or transitional doctypes, so you can choose which document type is best suited for your project.

<ul id="mainNav">
	<li>
		<a href="#">Articles
			<span class="lt"></span>
			<span class="rt"></span>
			<span class="lb"></span>
			<span class="rb"></span>
		</a>
	</li>
	<li>
		<a href="#">Links
			<span class="lt"></span>
			<span class="rt"></span>
			<span class="lb"></span>
			<span class="rb"></span>
		</a>
	</li>
	<li>
		<a href="#">Contact
			<span class="lt"></span>
			<span class="rt"></span>
			<span class="lb"></span>
			<span class="rb"></span>
		</a>
	</li>
	<li>
		<a href="#">Really Long Button
			<span class="lt"></span>
			<span class="rt"></span>
			<span class="lb"></span>
			<span class="rb"></span>
		</a>
	</li>	
</ul>

You'll notice that we've created an unordered list of links and that inside each link are four span elements. We'll be using the span elements as our corners and the classes given stand for leftTop, rightTop, leftBottom, and rightBottom respectively. We won't add a class to the anchor tags or list items because giving the unordered list element an id is sufficient to do what we want.

Creating an Image

CSS Corners Image

We're going to use just a single image for all of our corners, so let's create it now. Our page is going to have a light grey background using the color #CCCCCC, so first we will create a box the same color as the background. Because we're only going to have two different types of corners in this tutorial, the box is going to be 40px wide by 20px high.

Next we're going to create two circles, 20px by 20px, and place them side by side. The first we're going to give the color #0099FF and the second we'll give the color #333333. In your own work, add as many circles as you'd like and give them whatever colors you prefer. Just note that you'll have to adjust the CSS code to match your colors if you decide on using different colors.

Save two copies of the file: images/layout.png and images/layout-full.png. The first image file should be a flattened PNG file, preferrably PNG8 or PNG24 to reduce file size. This file will be our production file. The second file will be our working copy and should never be flattened. When you make changes, save layout-full.png and then flatten it and save it over layout.png as well.

Adding Some Rounded Style

Now it's time to put into practice what we've learned. I'll be using the short versions of some of the CSS declarations and compacting the code as much as possible, so if you see something you don't recognize, you can learn more about CSS syntax here. I'm going to give you the code first and then I'll follow up with the explanation.

/*Body*/
body {background:#CCC;}

/*Navigation Layout*/
#mainNav {padding:0; margin:0; list-style:none;}
#mainNav li {float:left; margin:1em 1em 0em;}
#mainNav li a {display:block; padding:.7em; background:#09F; color:#000; text-decoration:none; font-weight:bold; position:relative;}
#mainNav li a:hover {background:#333; color:#FFF;}

/*All Corners*/
.lt, .rt, .lb, .rb {background:url(images/layout.png); position:absolute; height:10px; width:10px; display:block;}
.lt, .lb {left:0px;}
.lt, .rt {top:0px;}
.rt, .rb {right:0px;}
.rb, .lb {bottom:0px;}

/*Specific Corners*/
#mainNav a .lt {background-position:0px 0px;}
#mainNav a .rt {background-position:-10px 0px;}
#mainNav a .lb {background-position:0px -10px;}
#mainNav a .rb {background-position:-10px -10px;}
#mainNav a:hover .lt {background-position:-20px 0px;}
#mainNav a:hover .rt {background-position:-30px 0px;}
#mainNav a:hover .lb {background-position:-20px -10px;}
#mainNav a:hover .rb {background-position:-30px -10px;}

Starting with the navigation layout, we zeroed both the padding and margin of #mainNav so that it will appear in the same spot in all browsers. The list-style:none; removes any bullets from the formating. Each list item was then floated left to make a horizontal menu and was given the appropriate spacing through the margin. Finally, each link was styled for both normal and hover states, with the hover state turning the button a different color. It's important to include both display:block; and position:relative; here because the anchor tag is our containing element. (Side note: The reason why an anchor tag must be used as the containing element is because it is the only element for which Internet Explorer 6 supports a hover state. If you wanted to use a different element other than the anchor tag, you'd have to find a JavaScript solution to get hover support.)

Because we have multiple types of corners, it's easiest to assign properties that all corners will share before dealing with specific corners. This method will also enable you to add additional corners later and it cuts down on file size because you won't have to duplicate code for each new corner. All of the corners will share the same background image, all will be the same size, and all will be set to position:absolute; and display:block;. I also grouped similar corners according to their shared positioning properties in order to reduce markup.

The last block of code assigns a background position to each corner type. Because all of the corners have already been assigned a background image at the same time, background-position is the only property left to assign the individual corners. The value for background-position always begins with the x-value and then the y-value and the pixel values are always negative except when they are zero.

The Good, the Bad, and IE6

Internet Explorer 6 is almost always a problem when it comes to layout issues and this is no exception. You may find that certain corners are offset by one or more pixels in IE6. If you are supporting IE6, the solution is simply to create a separate stylesheet that targets IE6 only and readjust the top, right, bottom, or left properties as needed.

To do that, include the stylesheet on your page surrounded by the following code, which will only be executed by IE6:

<!--[if lte IE 6]>
		<link type="text/css" rel="stylesheet" href="css/ie6.css" />
<![endif]-->

In some uses of this rounded corner method, you'll find Internet Explorer 6 also has a frustrating error that only appears when you dynamically resize the page. This error will cause a 1px margin to appear and disappear either to the left or the right of your corner image. The problem is because IE6 has a rounding error whenever the screen is an odd number of pixels wide and so it renders the corner element incorrectly. To the best of my knowledge, there is no cure for this problem in Internet Explorer 6.

Finally, you'll notice that there is a slight flickering when you hover over any of the menu items in IE6. This is because IE6 does not properly cache CSS background images and so it reloads them upon every request. To fix this problem, you'll have to include the one line of JavaScript that I warned you about at the beginning of the tutorial. Because this JavaScript code is only for IE6, you can place it right below your IE6-specific stylesheet.

<!--[if lte IE 6]>
		<link type="text/css" rel="stylesheet" href="css/ie6.css" />
		<script type="text/javascript">document.execCommand("BackgroundImageCache",false,true);</script>
<![endif]-->

Using Rounded Corners on Your Site

This method of rounding corners is great for certain use cases, but not so good for others. It's ideal if your design has solid color backgrounds, but if you make heavy use of gradients, you may want to find another method if you still want a fluid layout. Gradients are possible if you have a fixed widths and heights. If you want drop shadows, you'll probably also want to use another method or modify this one. Borders can be done, but they will take a few tries to perfect because the border line width can be tricky.

Despite the limitations, using the method of CSS rounded corners laid out in this tutorial has a lot of advantages if it fits your design. It's cross-browser, uses only one image, includes a hover state, and is completely CSS-based except for a single line to improve performance in IE6. We've used this method in our design in a number of different ways, so be sure to check out our stylesheet.

If you'd like more great design and programming tutorials and resources, follow us on Twitter for daily updates.

Tags

  • Benjamin Kuker

    Benjamin Kuker

    Benjamin Kuker is the co-founder of Virtuosi Media and is married to his beautiful wife, Johanna. He is responsible for the design and maintenance of this website. He enjoys reading, writing, programming, business, sports, and traveling.

    View Benjamin's Bio

Help us spread the word.

Your Comments Are Valuable - Join The Discussion!

 

Copyright 2011 Virtuosi Media Inc.