This week I went on a little Twitter rant about an HTML web site design I inherited last week and was required to turn into an Asp.Net project. I won't go into my rant on table based layouts as my good friend Lance Fisher pointed me to a definitive answer.... http://shouldiusetablesforlayout.com/.
After I got over the table based layouts I encountered this old school code for performing rollovers on the sites man menus.
<a href="index.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Home','','images/home_over.png',1)"><img src="images/home_out.png" name="Home" width="90" height="46" border="0" id="Home" /></a>
<a href="practice.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Practice','','images/practice_over.png',1)"><img src="images/practice_out.png" name="Practice" width="90" height="46" border="0" id="Practice" /></a>
<a href="physicians.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Physicians','','images/physicians_over.png',1)"><img src="images/physicians_out.png" name="Physicians" width="90" height="46" border="0" id="Physicians" /></a>
<a href="patients.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Patients','','images/patients_over.png',1)"><img src="images/patients_out.png" name="Patients" width="90" height="46" border="0" id="Patients" /></a>
<a href="contact.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Contact','','images/contact_over.png',1)"><img src="images/contact_out.png" name="Contact" width="90" height="46" border="0" id="Contact" /></a>
After seeing this code copy and pasted in every single page that we received from the designer (and taking a moment to cry) I went about cleaning up, I just can't work in copy and paste environment like this anymore.
Also, notice that all the menus where images, even though in reality they were just text. This made my life a little bit harder but I guess I'll let that one go for now.
Create a Master Page
First I created a master page and quickly replaced the repeated code about with something cleaner.
<ul class="navMenu">
<li id="HomeMenu"><a href="home.html">
<img src="/Content/images/home_out.png" alt="Home" />
</a></li>
<li id="PracticeMenu"><a href="Practice.html">
<img src="/Content/images/practice_out.png" alt="Practice" />
</a></li>
<li id="PhysiciansMenu"><a href="Physicians.html">
<img src="/Content/images/physicians_out.png" alt="Physicians" />
</a></li>
<li id="PatientsMenu"><a href="Patients.html">
<img src="/Content/images/patients_out.png" alt="Patients" />
</a></li>
<li id="ContactMenu"><a href="Contact.html">
<img src="/Content/images/contact_out.png" alt="Contact" />
</a></li>
</ul>
The key changes are:
- Added a list to layout the menu items
- Gave each menu item its own id
- Default each link content to be the out, or not selected, image
- Removed all the inline formatting and JavaScript calls
This is great I can actually look at this without cringing.
CSS Styles
The next step was to create the necessary CSS styles to implement the rollovers for the menu items. The plan behind the approach we chose to use was to set the content of the link to be the non-selected image and the background of the link to be the selected image. When the user hovers over the link then we will hide the link content (the non-selected image) resulting in the background image being displayed (the selected image). We're also going to use CSS to enforce some of the other formatting like height and width that were originally declared inline.
.navMenu
{
list-style-type:none;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
.navMenu li
{
float:left;
padding:0;
margin: 0;
width: 90px;
height: 46px;
}
.navMenu li img
{
width:100%;
height:100%;
border:0;
}
.navMenu a, .navMenu a:link, .navMenu a:visited
{
display:block;
}
.navMenu a:hover img
{
visibility:hidden;
}
#HomeMenu
{
background-image: url("/Content/images/home_over.png");
}
#PracticeMenu
{
background-image: url("/Content/images/practice_over.png");
}
#PhysiciansMenu
{
background-image: url("/Content/images/physicians_over.png");
}
#PatientsMenu
{
background-image: url("/Content/images/patients_over.png");
}
#ContactMenu
{
background-image: url("/Content/images/contact_over.png");
}
The first 4 .navMenu entries are nothing too exciting. Basically we're just formatting our list menu. the interesting line is what we do on the a:hover event.
.navMenu a:hover img
{
visibility:hidden;
}
What we're saying here in CSS speak is: "When the user moves their mouse over a link in .navMenu we want to hide any images inside of that link." This hides the image allowing us to see the background image then redisplays the image when the mouse is moved off of the link.
The second interesting things that we're doing is setting the selected image for each link item by using the background property.
#HomeMenu
{
background-image: url("/Content/images/home_over.png");
}
This is the part I like least about this solution because for each menu I need in my web site I have to add an entry to my CSS file. In this particular site the menus are static so that's not a big deal but if we were dynamically generating our menus we would definitely want to generate these pieces of the CSS file as well.
Setting the Selected Page Menu
The last thing we have to take care of is showing which menu is active. When the user is on the Home page we want the home menu to be selected and when the user is on the Contact page we want the Contact menu to be selected, etc.
We can accomplish this functionality by adding some custom CSS to each page that hides the default image for the menu item that we want to show as selected.
#ContactMenu a, #ContactMenu a:link, #ContactMenu a:visited
{
visibility:hidden;
}
This will result in the selected menu always showing the background image, which in our case is indicates that the image is selected.
Conclusion
A little CSS can go a long way. This is much cleaner than spattering that 'MM_swapImage' call everywhere and this approach gets even easier if you're not using images for displaying your menu items.