Build a Cross-Browser ASP.NET CSS-Only Menu UserControl

How to convert a CSS-only dropdown menu into an ASP.NET UserControl

When I was developing my "playground" site, ittyurl.net, I spent some time looking around at various top menu implementations. The requirements were that it had to be cross-browser, preferably CSS-only (no script), and reasonably self-contained. It also needed to be easy to modify and not take up a lot of "screen real estate". Among the dropdown menus I looked at were some of the creations of Stu Nicholls, who seems to have acquired quite a reputation for being a CSS guru.

I finally choose one of his CSS-only dropdown menus that I liked and decided that I would customize it and "roll it up" into an ASCX UserControl. The following code and downloadable sample solution show how I did this.

First, let's take a look at the markup of the CSSMenu.ascx control proper:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="CSSMenu.ascx.cs" Inherits="IttyUrl.menu.CSSMenu" %>
<link rel="stylesheet" media="all" type="text/css" href="css/dropdown.css" />
<!--[if lte IE 6]>
<link rel="stylesheet" media="all" type="text/css" href="css/dropdown_ie.css" />
<![endif]-->
<table cellpadding="0" cellspacing="0" border="0" width="100%" >
<tr >
<td valign="middle" style="width: 5px;border-width:0px;" ><img src="../images/menul.jpg" border="0" /></td>
<td >
<div class="menu" >
<ul>
<li><a class="hide" title="Home Page" href="./Default.aspx">HOME</a>
<!--[if lte IE 6]>
<a href="./Default">HOME
<table><tr><td>
<![endif]-->
<ul>
<li><a href="./AddUrl.aspx" title="Add a Url">ADD URL</a></li>
<li><a href="./IttyUrlService.asmx" title="IttyUrl API">API</a></li>
</ul>
<!--[if lte IE 6]>
</td></tr></table>
</a>
<![endif]-->
</li>
<li><a class="hide" title="Search" href="./Search.aspx">SEARCH</a>
<!--[if lte IE 6]>
<a href="./Search.aspx" title="Search">SEARCH
<table><tr><td>
<![endif]-->
<ul>
<li><a href="./Realtime.aspx" title="Tag Cloud">REALTIME SEARCH</a></li>
<li><a href="./Cloud.aspx" title="Tag Cloud">TAG CLOUD</a></li>
<li><a href="./MultiWebRequest.aspx" title="Multi Provider Search">MULTI-SEARCH</a></li>
<li><a href="./YouTube.aspx" title="YouTube Search">YOUTUBE SEARCH</a></li>
</ul>
<!--[if lte IE 6]>
</td></tr></table>
</a>
<![endif]-->
</li>
<li><a class="hide" href="./RecentLinks.aspx" title="Recent Links">LINKS</a>
<!--[if lte IE 6]>
<a href="./RecentLinks.aspx" title="Recent Links">LINKS
<table><tr><td>
<![endif]-->
<ul>
<li><a href="./GetLinksByUser.aspx" title="My Links">MY LINKS</a></li>
<li><a href="./GetLinksByTag.aspx" title="Links by Tag">LINKS BY TAG</a></li>
<li><a href="./SLtweets.aspx" title="Silverlight Tweets">SILVERLIGHT TWEETS</a></li>
</ul>
<!--[if lte IE 6]>
</td></tr></table>
</a>
<![endif]-->
</li>
<li><a class="hide" href="./MostPopular.aspx" title="Most Popular Links">TOOLS</a>
<!--[if lte IE 6]>
<a href="./MostPopular.aspx" title="Most Popular Links">TOOLS
<table><tr><td>
<![endif]-->
<ul>
<li><a href="./Groups.aspx?group=framework.aspnet" title="Microsoft Newsgroups">GROUPS</a></li>
<li><a href="./PopularRecent.aspx" title="Popular / Recent Searches">POPULAR SEARCHES</a></li>
<li><a href="./JobSearch.aspx" title="Job Search">JOB SEARCH</a></li>
</ul>
<!--[if lte IE 6]>
</td></tr></table>
</a>
<![endif]-->
</li>
<li><a class="hide" href="./MySearchesAndLinks.aspx" title="My Searches and Links">USER ITEMS</a>
<!--[if lte IE 6]>
<a href="./MySearchesAndLinks.aspx" title="My Searches and Links">USER ITEMS
<table><tr><td>
<![endif]-->
<ul>
<li><a href="./PageRank.aspx" title="Page Rank Check">PAGE RANK</a></li>
<li><a href="./CodeConvert.aspx" title="Code Converter">CONVERT</a></li>
<li><a href="./JSSqwincher.aspx" title="Javascript Sqwincher">JS SQWINCHER</a></li>
</ul>
<!--[if lte IE 6]>
</td></tr></table>
</a>
<![endif]-->
</li>
<li><a class="hide" href="./PopularLinks.aspx" title ="Popular Links">POPULAR</a>
<!--[if lte IE 6]>
<a href="./PopularLinks.aspx" title="Popular Links">POPULAR
<table><tr><td>
<![endif]-->
<ul>
<li><a href="./SiteSearch.aspx" title="Site Search">SITE SEARCH</a></li>
<li><a href="./KB.aspx" title="Microsoft LnowledgeBase Search">KB SEARCH</a></li>
</ul>
<!--[if lte IE 6]>
</td></tr></table>
</a>
<![endif]-->
</li>
<li><a class="hide" href="./UserPosts2.aspx" title="Top Blog Posts">TOP BLOGS</a>
<!--[if lte IE 6]>
<a href="./UserPosts2.aspx" title="Top Blog Posts">TOP BLOGS
<table><tr><td>
<![endif]-->
<ul>
<li><a href="./SubmitFeed.aspx" title="Submit a Feed">SUBMIT FEED</a></li>
<li><a href="./LatestBlogSearch.aspx"" title="Latest Blog Posts">LATEST POSTS</a></li>
<li><a href="./about.aspx" title="About Us">ABOUT</a></li>
</li>
</ul>
<!--[if lte IE 6]>
</td></tr></table>
</a>
<![endif]-->
</li>
</ul>
</div>
</td>
<td valign="bottom" style="width: 5px;border-width:0px;padding:2px 0 0 0"><img src="../images/menur.jpg" border="0" />
</td>
</tr>
</table>

You can see from looking at the above markup that we can create an ASCX UserControl simply by inserting the appropriate HTML and CSS we need from a non-.NET implementation. The only real modifications I needed to make were to surround the arrangement with a table to allow for containership of the left and right "rounded corners" background images. This allowed me to tweak the table cell styles to accomodate minor inconsistencies in the rendering among different browsers. You CSS purists would probably say I should have done that with CSS only, but I guess old habits die slowly. The CSS in the stylesheets provides all the rest. The CSS stylesheet links are embedded right into the control markup, which means that one does not need to add any CSS directives to a page or a MasterPage at all.

Nicholls uses some advanced CSS tricks that you can see by inspecting the dropdown.css stylesheet included in the solution. Among these are special "conditional" tags to make IE6 happy (Remember IE6? - Rest In Peace.). This menu should work with FireFox, Chrome, and at least Safari; I haven't tried Opera since I already have "too many" browsers installed on my machine! The menu also features nice tooltips that appear when the user mouses over a dropdown item or a main menu item.

Once this is done, the control can be added to a MasterPage in this manner:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site1.master.cs" Inherits="CSSMenu.Site1" %>
<%@ Register src="~/menu/CSSMenu.ascx" tagname="ucMenu" tagprefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<link rel="stylesheet" type="text/css" href="css/style.css" media="screen" />
</head>
<body>
<form id="form1" runat="server">
<asp:ContentPlaceHolder ID="menu" runat ="server">
<div id="xmenu">
<uc1:ucMenu ID="ucMenu1" runat="server" />
</div>
</asp:ContentPlaceHolder>
</form>
</body>
</html>

This will put the menu at the top of every page that specifies the given MasterPage. In the downloadable solution, I've also added one of our eggheadcafe.com wide banner ads, placing it in a DIV tag immediately below the menu, and you can see that when you mouse over a menu item, the dropdown list of subitems covers over the ad - allowing the user to click a menu item without invoking a click on the ad that is behind it. Of course, when one is simply viewing the page, you see the top menu area with the complete advertisement visible below it.

You can look at a working implementation of this by visiting
ittyurl.net here. The downloadable solution has both Visual Studio 2008 and Visual Studio 2010 solution files in it.

By Peter Bromberg   Popularity  (6562 Views)