Mission Impossible: A Diagonal Nav Rollover Effect with CSS

November 25th, 2008 in Design Tips & Tutorials

by: Matthew Griffin

The HTML rendering model is based on boxes. Every element of a web page is a box set on a grid. Now, this doesn't necessarily mean that our graphics all have to be  squares and rectangles. Over the years we've gotten pretty creative in our attempts to  break the grid (or at least create the illusion that we've broken the grid). Still, there are limitations we've come to accept. One of them is the inability to build an overlapping diagonal navigation. Without using image maps and complicated Javascript, it's a task that seems almost impossible. In this article, I'm going to share a method I developed to overcome the problem. When you're finished with the tutorial, you'll have a simple, semantic, diagonal set of navigation buttons (rollover effect included).


In this example, I'm not going to build a complete layout. You can search through my other articles for that. Instead, I'm going to focus in on the header and the navigation. If you want to see the end result, go HERE for a live working example. Here's the XHTML you should start with:

<div id="header">
    <ul class="nav">
        <li class="home"><a href="#">Home</a></li>
        <li class="about"><a href="#">About Us</a></li>
        <li class="downloads"><a href="#">Downloads</a></li>
        <li class="contact"><a href="#">Contact Us</a></li>

Put this XHTML into the body tag of your page. As you can see, we are starting with simple semantic markup that will degrade gracefully in just about any browser.

Building Buttons

For now, I'm going to leave the markup alone and show you how to set up your button graphics. For this example you will need to build four link buttons. Each button will be exactly 200px high and 149px wide with a transparent background. Once you have the inactive state button finished, you need to double the height of the canvas at the bottom. Then you will duplicate your button on the bottom half of the canvas. The duplicate button will serve as the active state button so you will need change its color accordingly. When you're finished, you should have something like this:

If you don't want to take the time to build it yourself, you can download the Photoshop file HERE.

Now that you have your button ready, go to FILE>>SAVE FOR WEB. Set the format to GIF, maintain the transparency with a white matte, and save the file as 001.gif (this will be the home link button) in a directory that's easily accessible to the XHTML page you built earlier. Once you're finished, repeat the process for three more buttons, naming them 002.gif (About Us), 003.gif (Downloads), and 004.gif (Contact Us) respectively.

Styling the Diagonal Nav

Okay, at this point, you should have a web page with navigational links and all of your buttons ready to go. All you have to do now is make them look good. Go ahead and add this CSS to your document:

    margin: 0;
    padding: 0;
#header {
    width: 400px;
    height: 150px;
    overflow: hidden;
    margin: 10px;
    border-top: 5px solid #000;
#header .nav li {
    position: absolute;
    list-style: none;
#header .nav li a {
    display: block;
    width: 200px;
    height: 150px;
    text-indent: -9999px;

#header .nav li.home { left: 0; }
#header .nav li.home a { background:url(images/diagonal_nav/001.gif) no-repeat; }
#header .nav li.home a:hover { background:url(images/diagonal_nav/001.gif) no-repeat 0 -200px; }

#header .nav li.about { left: 60px; }
#header .nav li.about a { background:url(images/diagonal_nav/002.gif) no-repeat; }
#header .nav li.about a:hover { background:url(images/diagonal_nav/002.gif) no-repeat 0 -200px; }

#header .nav li.downloads { left: 120px; }
#header .nav li.downloads a { background:url(images/diagonal_nav/003.gif) no-repeat; }
#header .nav li.downloads a:hover { background:url(images/diagonal_nav/003.gif) no-repeat 0 -200px; }

#header .nav li.contact { left: 180px; }
#header .nav li.contact a { background:url(images/diagonal_nav/004.gif) no-repeat; }
#header .nav li.contact a:hover { background:url(images/diagonal_nav/004.gif) no-repeat 0 -200px; }

For the purposes of this example I placed the CSS in the head of the XHTML document, but you can pull it in with a link tag just as easily. The first block of CSS code you see resets the padding and margin on all HTML elements. The asterisk just means "everything".

In the next block where the #header is being styled, notice that the position is set to "relative". This is important because we need to be able to set nav buttons to absolute positions within the header div. If you left that attribute alone, and tried to absolutely position your buttons, you would find that they would position themselves in relation to the whole page rather than in relation to the #header div.

Next, you can see that the list items and links within the .nav list are being styled with general attributes. The lis are set to position: absolute so we can overlap the nav buttons. The links inside the .nav lis are set to display:block. This makes them function like a div functions, rather than inline. Next, the links are set to the height and width of a single nave button (200x150), and the text within the link is indented far enough negatively to make it invisible. Search engines and certain old or mobile browsers can still see the text links, but modern browsers will display only the cool button graphics.

Finally, at the bottom of the CSS code, you will see our styles for the individual buttons. Each nav button has a corresponding three lines of code. The first line positions the button a certain number of pixels away from the left corner of the #header div. The next line sets the background of the link to the corresponding button graphic. And the last line changes the position of the nav graphic when the mouse is placed over the button. This exposes the bottom half of the nav graphic so the active state is visible.

Of course, we haven't actually broken the grid model at all. We've only manipulated the visual output by overlapping buttons with transparent backgrounds. The active link areas are still boxes.

When you preview the page in a browser, the result should look like this:

You can also stagger the buttons from the top for an effect that looks like this:

For a full working example go HERE.



Posted By: Wes P on 11/25/08

I'm not, by any means, attempting to trivialize the process of making diagonal buttons. I've been challenged in the past with this same feat, however it always ended in one of 2 ways. 1, the diagonals were removed, or 2 it was modified so the diagonals didn't overlap, and weren't actually part of the link. Not to be critical, but when I move my cursor down to the bottom of the nav button (FF 3), the nav button to the left becomes hovered. This is my primary concern with doing things like this. Don't get me wrong, it's a great effect, and would be awesome to be able to do, I've just never found it functionally practical to do, unless you're in Flash, or perform some horrid semantically nightmarish HTML, or as you mentioned in the article, use image maps, or complex JS. As always, I love reading this blog. Keep it coming :)

Posted By: Matthew Grffin on 11/25/08

Wes, it's true that there isn't a perfect solution using just CSS at this point. But this one is very close and acceptably functional in my experience.

Posted By: Jason Cochran on 11/25/08

Got flash? :)

Posted By: Reggie on 11/26/08

I had the same problem as Wes P, and I expect everyone will share the problem, of the lower half of the buttons hilighting the wrong target. But that is a calculated functional sacrifice made for the gains in design flexibility. Not a huge issue for me. But my comment is on the buttons "stacked" creation. I can't believe I hadn't thought of that yet!! eeks! It's so simple! The problem of the flashing button as the new image loads is always an issue to overcome. I've overlapped buttons and set the top one to "hidden" on hover so the second image is preloaded. I've never used the method of preloading images outside of the field of view because some browsers detect this and add a scroll bar on my otherwise nice designs. But to "shift" the image on hover... it's so simple and elegant, it's brilliant! I feel enlightened and a little bit silly that I've not considered this before. Thank you!

Posted By: Matthew Grffin on 11/26/08

Thanks for the comment, Reggie.

Posted By: paul on 11/26/08

Very elegant and easy to understand. Thanks for sharing!

Posted By: Matt Garvin on 12/02/08

> One of them is the inability to build > an overlapping diagonal navigation. > Without using image maps and > complicated Javascript, it's a task > that seems almost impossible. Not to be snarky, but how come "without using imagemaps"? With image maps and some simple javascript, achieving this same effect would be easy? Matt Garvin PS: Great site by the way!

Posted By: Matt Garvin on 12/02/08

Yuck. Me no like the way my post ^ got formatted. Sorry about that...

Posted By: Matthew Grffin on 12/02/08

Matt, no problem. The point here is to try to achieve the effect while maintaining semantic purity. The example in this article will work no matter what browser/setup the user is on. JavaScript is good when its functions as an additional layer on top of a site that will work with or without Javascript enabled. That's what I'm trying to accomplish here.

Posted By: Clubturk.net-2. Seo Yarismasi on 04/27/09

Very elegant and easy to understand

Posted By: Michael G. on 10/29/09

Thanks that was extremely helpful. I am incorporating this on my site in a different way. brand7.net/test

Posted By: Matthew Griffin on 10/29/09

Looks good, Michael G. Glad it helped.

Posted By: Jeff on 11/18/09

I'd probably opt to use image maps =)

Posted By: Michael G. on 12/02/09

Image maps are hideous, a very old way of doing a certain task for a site. At least look at jquery Jeff, its ways better and easy to implement.

Posted By: Baby Photography Toronto on 12/15/09

Love your blog matt.....thanks again for the sharing of info..i always find it easy to understand your articles and instructions. :)

Posted By: Ryan Huber on 01/26/10

Great Tutorial! Many thanks. Will be implementing on my redesign. Anyone every use jquery animate along with this effect?

Post Your Comment

Comments are closed.