views:

1450

answers:

4

Hi all,

I've built a CSS navigation menu using a sprite, very similar to the one on Apple's website. I've got it working fine, such that it changes to the right position on the image on hover and mousedown (all using CSS), but I'm having a hard time figuring out how to make a button stay highlighted once it's clicked. I have a row in my sprite for the "clicked" look, but there's no CSS that I know of to handle something that's selected. I want the buttons to turn to their "clicked" version, depending on which one has been clicked. I've explored some javascript solutions, using jQuery, but I thought there might be a better way.

The sprite I'm using is very similar to Apple's, found here.

Any help would be greatly appreciated. Thanks.

More Info:

So my menu currently looks like this in html:

    <ul id="global_nav">
        <li id="home_nav"><a href="<%= Url.Action("Index", "Home") %>"></a></li>
        <li id="systems_nav"><a href="<%= Url.Action("Index", "Home")%>"></a></li>
        <li id="users_nav"><a href="<%= Url.Action("Index", "Home")%>"></a></li>
        <li id="utilities_nav"><a href="<%= Url.Action("Index", "Utilities")%>"></a></li>
        <li id="reference_nav"><a href="<%= Url.Action("Index", "Home")%>"></a></li>
        <li id="metrics_nav"><a href="<%= Url.Action("Index", "Home")%>"></a></li>
        <li id="help_nav"><a href="<%= Url.Action("Index", "Home")%>"></a></li>
        <li id="info_nav"></li>
    </ul>

Any my CSS is all here (sorry, it's long):

#global_nav 
{
    background: url("../Images/nav_bar.png");
    height: 38px;
    width: 979px;
    padding: 0;
    list-style-image: none;
    list-style-position: outside;
    list-style-type: none;
}

#global_nav li
{
    float: left;
}

#global_nav a 
{
    height: 38px;
    display: block;
}

#global_nav #home_nav 
{
    width: 118px;
}

#global_nav #home_nav a:hover 
{
    background: url("../Images/nav_bar.png") 0px -37px no-repeat;
}

#global_nav #home_nav a:active
{
    background: url("../Images/nav_bar.png") 0px -74px no-repeat;
}

#global_nav #systems_nav
{
    width: 116px;
}

#global_nav #systems_nav a:hover 
{
    background: url("../Images/nav_bar.png") -118px -37px no-repeat;
}

#global_nav #systems_nav a:active
{
    background: url("../Images/nav_bar.png") -118px -74px no-repeat;
}

#global_nav #users_nav
{
    width: 117px;
}

#global_nav #users_nav a:hover 
{
    background: url("../Images/nav_bar.png") -234px -37px no-repeat;
}

#global_nav #users_nav a:active
{
    background: url("../Images/nav_bar.png") -234px -74px no-repeat;
}

#global_nav #utilities_nav
{
    width: 117px;
}

#global_nav #utilities_nav a:hover 
{
    background: url("../Images/nav_bar.png") -351px -37px no-repeat;
}

#global_nav #utilities_nav a:active
{
    background: url("../Images/nav_bar.png") -351px -74px no-repeat;
}

#global_nav #reference_nav
{
    width: 117px;
}

#global_nav #reference_nav a:hover 
{
    background: url("../Images/nav_bar.png") -468px -37px no-repeat;
}

#global_nav #reference_nav a:active
{
    background: url("../Images/nav_bar.png") -468px -74px no-repeat;
}

#global_nav #metrics_nav
{
    width: 117px;
}

#global_nav #metrics_nav a:hover 
{
    background: url("../Images/nav_bar.png") -585px -37px no-repeat;
}

#global_nav #metrics_nav a:active
{
    background: url("../Images/nav_bar.png") -585px -74px no-repeat;
}

#global_nav #help_nav
{
    width: 117px;
}

#global_nav #help_nav a:hover 
{
    background: url("../Images/nav_bar.png") -702px -37px no-repeat;
}

#global_nav #help_nav a:active
{
    background: url("../Images/nav_bar.png") -702px -74px no-repeat;
}

#global_nav #info_nav
{
    width: 163px;
}

#global_nav #info_nav a:hover 
{
    background: url("../Images/nav_bar.png") -819px -37px no-repeat;
}

#global_nav #info_nav a:active
{
    background: url("../Images/nav_bar.png") -819px -74px no-repeat;
}
+1  A: 

CSS doesn't know or care what page it's on. You have to track that and output the relevant markup yourself.

Azeem.Butt
A: 

Do you use a server-side programming/scripting language like PHP/ASP/JSP? If so, then you can just render a CSS class conditionally. Here's a PHP example (you can get requested page in PHP by one of the $_SERVER variables):

<a href="somepage"<?php echo ($currentpage == 'somepage' ? ' class="active"' : ''); ?>>somepage</a>

If you don't use a server side language, then the only resort is JS/jQuery. Do something like following during onload (you can get requested page in JS by parsing the window.location):

$('a[href="' + currentpage + '"]').addClass('active');

The CSS class a.active should obviously shift the background-position so that it becomes "active".

BalusC
@BalusC, thanks for the response. This is done using ASP.NET MVC. I've been using jQuery for all javascript work. How would you recommend me handling the removal of the class once a different button is clicked? Thanks.
Mega Matt
That's not needed as links just generate synchronous requests. And, if you're using a server side language like ASP, then I strongly recommend to do it over there and not in jQuery.
BalusC
I guess I'm having a hard time understanding what class I would add. Each button requires a different position on the image sprite, so I wouldn't be able to create a single class (like .active), because the position has to change depending on which button is clicked. Would I need to create a class for each button, each with a different background position? Also, I'm not sure I follow your last commend about synchronous requests. I feel like once a class is added to a `<li>`, it must be removed for it to go back to it's "default" look...
Mega Matt
Just add a class which shifts the `background-position` in y-axis (assuming you're using same image template layout as apple did).
BalusC
I'm not sure I know of a way to only shift the background-position on the y axis. I need to give it a number for the x-axis, and that's what's going to vary depending on what's clicked..
Mega Matt
A: 

Self-Answer:

To do this I essentially followed the way Apple does it on their site. I set a div with a width of the sprite, and added an unordered list within this div. Each list item represents a button along the button bar. Within each list item there is a single anchor tag that href's to the page that I want to go to when the button is clicked. In the CSS, I have a class that refers to all anchor tags under a list item under the containing div, under it's div, as such:

#globalheader #globalnav li a
{
    float: left;
    height: 0;
    overflow: hidden;
    padding-top: 36px;
    width: 118px;
    background-image: url("../Images/nav/nav_bar.png");
    background-repeat: no-repeat;
}

This defines a background image for each of the anchor tags. Now I need to define the background position for each anchor tag, so it shows the right button. I have CSS for each anchor tag. Here's the CSS for one of them:

#globalheader #globalnav li#systems_nav a 
{
    background-position: -118px 0;
}

Of course I have CSS to handle the hover over the buttons (a:hover) and for the mousedown over the buttons (a:active), but my original question dealt with how to keep it on the selected look for the button when I'm on a certain page. I'll start with the CSS. If I had 6 buttons, I made six more CSS classes, each one pertaining to the container div having a certain class. That class the container has will be based on the page I'm currently on (I'll explain in a minute). Also within the definition of that CSS class, I specify which anchor tag to change the background position on. As an example, if I click the "Systems" button on the page, I will dynamically add (via javascript) a class to the container div of "systems", and this CSS will be applied as a result:

#globalheader.systems #globalnav li#systems_nav a
{
    background-position: -118px -108px !important;
}

The background position is the one that covers the "clicked" look for my button. Note the .systems part of the declaration that specifies that the #globalheader div must have a class of "systems". If this is the case, it changes the background position of only a single anchor tag: you guessed it, the one right under the "systems_nav" li. I wrote one of these classes for each of the buttons in the button bar. The second trick was writing the javascript to handle dynamically adding the class to the div depending on what page I was on. To do this, I put a hidden div on each page that looked something like this:

<div id="page_section" title="systems" style="display: none;"></div>

It's not displayed, has a generic id that each of these divs will have on each page on my site, and has a title specific to the page I'm on. In my javascript file, I wrote this (it uses jquery):

var $globalheader = $('#globalheader'); // container div to add the class to
var $page_section = $('#page_section'); // div whose title is the current page

$globalheader.addClass($page_section.attr('title'));

Voila. "systems" gets added as the class name to the "globalheader" div, and the correct CSS class gets applied, making only the Systems button look clicked.

This took a little work by looking at Apple's website, but this is how they do it, and I trust them. It worked for me.

Hope it helps anyone else having the same problem I was.

Mega Matt
A: 

@BalusC I tried using your PHP example but am struggling. I have all the correct classes set up and have tested each link with the class set to active and it shows the image I want to use for the currently selected page. However, for some reason, the code is not passing the correct info to set the class to active in my code, which is as follows:

<li id="menu01"><a href="index.php" title="Gravell & Company Home" <?php echo ($currentpage == 'index.php' ? ' class="active"' : ''); ?>><span>Home</span></a></li>

Any suggestions or comments on what I may be missing?