Search code examples
asp.netcssmenupseudo-class

Asp.NET 4.0 Menu control a:active style persisting after mouse released


I'm using a standard asp.net menu in an asp.net 4.0 web application. To clarify, it's a standard web application, it is not any version of the MVC applications available.

This is the problem I'm having.

It's a fairly simple setup really. I have css overing the various states of the menu, :link, :visited, :hover and :active.

As you would suspect, there are visible differences between these states. In addition, I have some javascript running which highlights the link of the current page, which is another fairly normal activity. Nothing mysterious or obcure so far.

The problem comes when people start clicking around on the menu. Lets say you are on the home page. The first menu item is highlighted. Lets say now - for whatever reason only a user can come up with - you click and drag one of the menuitems. It doesn't have to be far, it can be only a millimetre or two. The expected behaviour is that the drag will negate the click, the page will stay where it is and the click-dragged menuitemw ill return to its former state.

What actually happens is the drag negates the click, the page stays where it is and the click-dragged menuitem seems to retain the :active style if it exists, or the :hover style if the :active style isn't there.

Replication:

It would appear this could be a bug in the Asp.Net menu though.

To try to replicate the problem outside my project, I created a bog standard Asp.NET Web Application project using the template in VS2010.

I changed one line in the Site.css - specifically, I changed the :active style in div.menu ul li a:active to color: red;

Then I fired the application up, clicked the Home menu item and dragged it a couple of millimetres.

Sure enough, when I let go of the mousebutton, the menu item stuck with the :active style.

Testing

I originally found the problem in IE8, however it is still there in IE9 as well as in Firefox/Aurora.

Chrome and Safari however, revert the menu item back to its intended state, mostly. They both leave a glowy effect around the edges of the element. I haven't tested it in Opera.

....Profit?

I've scoured the net looking for a solution to this and just cannot find one. In fact, it's very tough to find a reference to the problem, the closest I came was on one of Sitepoint's reference pages, where it mentions something similar as a bug in IE7.

http://reference.sitepoint.com/css/pseudoclass-hover

Anyone have any ideas?

Code

Here is the code in the Site.Master - I've renamed menu items to protect the culpable:

<div class="topnav">
    <asp:menu id="topnav" runat="server" orientation="Horizontal" renderingmode="List" skiplinktext="" maximumdynamicdisplaylevels="1" viewstatemode="Enabled" >
        <items>
            <asp:menuitem navigateurl="~/Default.aspx" text="Home" value="home"></asp:menuitem>
            <asp:menuitem navigateurl="~/Overview.aspx" text="Overview" value="overview"></asp:menuitem>
            <asp:menuitem navigateurl="~/Benefits.aspx" text="Benefits" value="benefits"></asp:menuitem>
            <asp:menuitem navigateurl="~/Hardware.aspx" text="Hardware" value="hardware"></asp:menuitem>
            <asp:menuitem navigateurl="~/SDK.aspx" text="Develop" value="SDK"></asp:menuitem>
        </items>
    </asp:menu>
</div>

While I'm at it, I'll also post the CSS which applies to this menu.

.right .topnavcont
{
    width: 767px;
    background-color: #dddddd !important;
    height: 22px;
}

.topnav #topnav li
{
    float: left;
}

.topnav
{
    background-color: #ddd;      
    line-height: 22px;
    float: right;
    margin-right: 11px;
    background: url(../img/shadow.gif) repeat-y top right;
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 12px;
    font-weight: bold;
    color: #777;
    text-align: center;
}

.topnav li
{
    width: 109px;
}

.topnav a:link, .topnav a:visited
{
    color: #777;
    display: block;
    background-image: url(../img/bg_n-s.gif);
    background-repeat: repeat-x;
    text-decoration: none;
    visibility: visible;
}

.topnav  a:hover
{
    color: #fff !important;
    background-image: url(../img/bg_h-s.gif);
    display: block;
    visibility: visible;
}

.topnav a:active
{
    background-image: url(../img/bg_a-s.gif);
    display: block;
    color: #fff;
    visibility: visible;
}

.topnav .current
{
    color: #fff !important;
    background-image: url(../img/bg_h-s.gif) !important;
}

And last but not least, the javascript I have running on the page to assist with this menu.

$(function ()
{
    var pathname = (window.location.pathname.match(/[^\/]+$/)[0]);
    $('.topnav ul li a').each(function ()
    {
        if ($(this).attr('href') == pathname)
        {
            $(this).addClass('current');
        }
    });
});

Solution

  • After tearing my hair out and considering a career in basket weaving, I think I have managed to come up with a half baked solution to this.

    The secret lies in the Asp.Net Menu control's complete failure to deal properly with css pseudo classes.

    In my code above, you could see I had defined an a:active pseudoclass, which was where the problem lay.

    Asp.Net doesn't want you to use pseudo classes, it wants you to use the properties exposed in the web control at design time. So, instead of just sticking with the age old :link:visited:hover:active pseudoclasses, you are instead supposed to set the property staticselectedstyle-cssclass.

    Not necessarily a bad thing, although it does seem a little verbose and counterintuitive.

    The thing to remember though is to ensure a :active pseudo class targetting the element isn't preceding the staticselectedstyle-cssclass code, because for some reason, the browsers seem to only pick up bits and pieces from each class, getting things all wrong in the meantime.

    So now, my css for the topnav looks like this:

    .topnav
    {
        background-color: #ddd;
        /*margin-top: 1px;*/
        line-height: 22px;
        float: right;
        margin-right: 11px;
        background: url(../img/shadow.gif) repeat-y top right;
    
    
        font-family: Verdana, Arial, Helvetica, sans-serif;
        font-size: 12px;
        font-weight: bold;
        color: #777;
        text-align: center;
    }
    
    .topnav #topnav li
    {
        float: left;
    }
    
    .right .topnavcont
    {
        width: 767px;
        background-color: #dddddd !important;
        height: 22px;
    }
    
    .topnav li
    {
        width: 109px;
    }
    
    .topnav a:link, .topnav a:visited
    {
        color: #777;
        display: block;
        background-image: url(../img/bg_n-s.gif);
        background-repeat: repeat-x;
        text-decoration: none;
        visibility: visible;
    }
    
    .topnav  a:hover 
    {
        color: #fff !important;
        background-image: url(../img/bg_h-s.gif);
        display: block;
        visibility: visible;
    }
    
    topnav .staticmenuitemselected
    {
        color: #777;
        display: block;
        background-image: url(../img/bg_n-s.gif);
        background-repeat: repeat-x;
        text-decoration: none;
        visibility: visible;
    }
    

    I have not yet completely finished experimenting with the :active pseudoclass though, since I do want the act of clicking a button on the menu to give me a warm fuzzy glow when it does that flashy clicky thing.

    Thanks for reading/hope this helps someone.