JavaScript Set CSS Class based on URL

I’ve got the following menu:

	    <div id="menu">
		    <ul>
			    <li class="current_page_item"><a class="menuBow" href="default.aspx">home</a></li>
			    <li><a href="about.aspx">about</a></li>
			    <li><a href="contact.aspx">contact</a></li>
		    </ul>
	    </div>

I need to set the class to current_page_item based on the selected hyperlink. Any examples out there that you might have? I need to probably base it on the url of the current page, I don’t see any other way.

You can use a CSS-only method, but it requires a little server-side code:

<body id="home">
	    <div id="menu">
		    <ul>
			    <li id="menu-home"><a class="menuBow" href="default.aspx">home</a></li>
			    <li id="menu-about"><a href="about.aspx">about</a></li>
			    <li id="menu-contact"><a href="contact.aspx">contact</a></li>
		    </ul>
	    </div>
</body>

#home #menu-home,
#about #menu-about,
#contact #menu-contact {
  background: red;
}

Then you just need to change the ID of the body tag for each page using server-side code, which will automatically trigger the appropriate “highlighting” CSS for the current menu item.

Interesting, did not know you could do this without JavaScript

One issue or possible limitation with your solution…it’s not dynamic enough. Initially when the page loads, we have the Home selected (default.aspx). While yours may work, how would I set the css to no style css=“” or something to essentially unselect the default selected menu item?

Also, if you’re using a master page, you’re only going to have one body tag for all your pages.

No matter what he will have to use 1 body tag. The ID’s will be different. I’m not sure I understand what you are talking about. You want some way of removing the styles from the current page link? You could remove the class via Javascript but why would you want to do that?

Here, I’ll cut to the chase…

http://www.visibilityinherit.com/code/current-page.php

Ok, here we go again:

  1. Page loads, home tab is “selected”, hence class=“current_page_item”
  2. I click About. Ok, now I need to set the link for default.aspx to nothing as I want to unselected, then I need to set the class for the About link to lass=“current_page_item”

that’s why you can’t just do this all in CSS. The unselecting / changing of the default’s lass=“current_page_item” to nothing can’t be done at the same time you set the about link to lass=“current_page_item”. That’s dynamic CSS with JavaScript, There’s no way I can do both actions in CSS…it’s impossible right?

As far as the body tag, I’m using an asp.net master page that holds the body for any page inheriting from it. So we’re not going to have body tags in every page. It inherits the master body tag

EricWatson thanks but it doesn’t change the Home class and essentially unselect it. That’s why I figure I am going to have to resort to JavaScript for this.

Hi,

I don’t quite understand what your looking for, but I’ve used this JS to highlight the current page before. Might work for you…

http://www.visibilityinherit.com/code/current-page-withjs.php

I see. Ok, yea, that would work.

Now, I’m looking at your JS code. How are you unselecting (chaning the css class) of the previous selected element when you select a new element as to clear the one that you had highlighted before selecting a different menu item?

I thikn I see how you’re clearing it I think…

weird, can’t get yours to work. I must be missing something simple here:



#menu a:hover {
	color: #FFFFFF;
	background: url(images/buttonGrey.jpg) no-repeat;	
}

#menu a.menuHighlight
{
	color: #FFFFFF;
	background: url(images/buttonRed.jpg) no-repeat;	
}

<script type="text/javascript">
var current = document.getElementById('default');

  function highlite(el)
  {
     if (current != null)
     {
         current.className = "";
     }
     el.className = "menuHighlight";
     current = el;
  }
</script> 

<div id="header">
    <div id="headerContent">
	    <div id="menu">
		    <ul>
			    <li class="current_page_item"><a id="default" class="menuHighlight" onclick="highlite(this);" href="default.aspx">home</a></li>

			    <li><a href="about.aspx" onclick="highlite(this);">about</a></li>
			    <li><a href="contact.aspx" onclick="highlite(this);">contact</a></li>
		    </ul>
	    </div>
        <div class="photo">
            <h2><a id="Header1_HeaderTitle" title="The Title Of Page." href="/Default.aspx">The dfgfgd</a></h2>

            <div id="tagline">The...</div>

        </div>
        <div class="bodyLineSeperator"></div>
    </div>
</div>

Also, if you’re using a master page, you’re only going to have one body tag for all your pages.

Not necessarily, this depends on how smart you programmed it to be. The ideal solution is to use some sort of variable such as $_GET[‘page’] which corresponds to the page, so if you linked to say the about page, linked it as index.php?page=about

And use the $_GET[‘page’] to echo the class name in the body, such as <body class=“section-<?php echo $_GET[‘page’]; ?>”> ( though you might wanna check if its defined ).

Though I would never do this personally, if you really want to rely on JS alone it’s not preferred to have inline event handlers and the like as it isn’t as flexible as unobtrusive code, I would do it as such:

<!doctype html>
<html>
    <head>
	<title>one active state</title>
        <script type="text/javascript" src="foo.js"></script>
	<style type="text/css">
	    * { margin:0; padding:0; }

	    body {
		font:76&#37; verdana;
		padding:10em 0 0;
	    }

	    ul#nav {
		background:#333;
		list-style:none;
		margin:0 auto;
		padding:1em;
		width:10em;
	    }

	    ul#nav li {
		display:block;
		width:100px;
		margin:0 0 10px;
	    }

	    ul#nav li a:visited, ul#nav li a:link {
		color:#fff;
	    }

	    ul#nav li.current a {
		color:red;
	    }

	</style>
    </head>

    <body>

	<ul id="nav">
	    <li class="current"><a href="#">Home</a></li>
	    <li><a href="#">Contact Us</a></li>
	    <li><a href="#">About</a></li>
	    <li><a href="#">Tools</a></li>
	    <li><a href="#">Services</a></li>
	    <li><a href="#">Hiring</a></li>
	</ul>

	<script>
(function() {
        var addEvent = (function() {
            return window.addEventListener ?
            function( el, ev, fn ) {
                el.addEventListener( ev, fn, false );
            }
            :
            function ( el, ev, fn ) {
                el.attachEvent( 'on' + ev, function() {
                fn.call( el );
                });
            }
        })(),
 
            hasClass = function( el, className ) {
            return (' ' + el.className + ' ').indexOf( ' ' + className + ' ') != -1;
            },
 
            getElementsByClass = function(c, node, tag) {
            node = node || document;
            var els = tag || '*';
            var elements = node.getElementsByTagName(els);
            var matchedArray = [];
            for (var i=0, l=elements.length; i<l; i++) {
                if ( hasClass ( elements[i], c ) ) {
                matchedArray.push(elements[i]);
                }
            }
            return matchedArray;
            }
 
            addClass = function( c, e ) {
            e.className += c;
            };
 
            removeClass = function( c, e ) {
            e.className = e.className.replace( c, '' );
            };
 
 
        if ( typeof Array.prototype.forEach == 'undefined' ) {
            Array.prototype.forEach = function( fn ) {
            var len = this.length, thisp = arguments[1];
            for ( var i = 0; i<len; ++i ) {
                fn.call( thisp, this[i], i, this );
            }
            }
        }
 
        addEvent( window, 'load', init );
 
        function init() {
            var nav = document.getElementById( 'nav' ), // update nav ID here
            activeClass = 'current', // update current class here
            current = getElementsByClass( activeClass, nav, 'li' )[0],
            lis = nav.getElementsByTagName('li');
 
            // since we're dealing with a nodeList
            Array.prototype.forEach.call( lis, function( el ) {
            addEvent( el, 'click', function( e ) {
                if ( !hasClass( this, activeClass ) ) {
                removeClass( activeClass, current );
                addClass( activeClass, el );
                current = el;
                if ( e.preventDefault ) {
                    e.preventDefault();
                } else {
                    e.returnValue = false;
                }
                }
            });
            });
 
        }
        })();
	

</script>

To get the JS block I typed to function correctly, the easiest way is to place the <script> tags before the </body> end tag. An alternative would be invoking this on window’s load event, or on dom ready.

Eventually I’m just going to use JQuery for the unobtrusive code, but for now just trying to get it working in JavaScript in a simple script.

If that’s implying I’m using jQuery ( maybe the syntax confused you? ) - I’m not. The simpler it is, the less it takes account for and I’d say mine is pretty decent.

Yes, I do have some generic functions defined because it’s just cleaner to me and more maintainable in that you can re-use those functions. Otherwise you’d code a script very specific to the code at hand and it would not be reusable without heavy modification for future use.

weird. It appears that it does change it to red but very briefly as if the page refresh is causing it to loose the css class change made to the selected item:



<script type="text/javascript">
 var current = document.getElementById('defaultMenuHighlight');

  function highlite(el)
  {
     if (current != null)
     {
         current.className = "";
     }
     el.className = "menuHighlight";
     current = el;
  }
</script> 


<div id="header">
    <div id="headerContent">
	    <div id="menu">
		    <ul>
			    <li><a id="defaultMenuHighlight" class="menuHighlight" onclick="highlite(this)" href="default.aspx">home</a></li>

			    <li><a href="about.aspx" onclick="highlite(this);">about</a></li>
			    <li><a href="contact.aspx" onclick="highlite(this);">contact</a></li>
		    </ul>
	    </div>
        <div class="photo">
            <h2><a id="Header1_HeaderTitle" title="The Title" href="/Default.aspx">The Gadfg</a></h2>

            <div id="tagline">The...</div>

        </div>
        <div class="lineSeperator"></div>
    </div>
</div>

#menu a:hover {
	color: #FFFFFF;
	background: url(images/buttongrey.jpg) no-repeat;	
}

#menu a.menuHighlight
{
	color: #FFFFFF; 
	background: url(images/button.jpg) no-repeat;	
}

****, why do I get a page refresh. I’m losing the damn css value that it changes to. This is asp.net but it’s a simple hyperlink so that makes no difference.

No, I’m not saying you’re using JQuery, I’m saying I will be using it later…will replace the JavaScript with Some simple JQuery instead…

Yes, that’s exactly what’s happening because the code in http://www.visibilityinherit.com/code/current-page-withjs.php works only because the href is set to a hash mark, which means it links to the same page and no refresh happens. As soon as you replace the hash with a real link it doesn’t work, meaning unless you’re going to do Ajax/iFrames you won’t be able to do this in Javascript.

actually they must be ajax IFrames because I do not get a full page refresh. I’m using Subtext

?!!?

why do I get a page refresh

I’m confused.