Disabling the current page menu button

The CSS matching pairs technique allows us to use the same HTML menu code on several pages and have the tab/button for the current page highlight automatically. An important menu consideration is that the tab for the current page should be non-clickable; ie, clicking the current page button should not reload the page.

The following code demonstrates the matching pairs technique for highlighting the current page button and adds a technique that renders the current tag non-clickable. This particular technique is not semantically cool, but it is very easy to code and bullet-proof as far as I can tell.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>non-clickable current page menu button</title>
    <style type="text/css">
*, *:before, *:after {
    -webkit-box-sizing:border-box;
    -moz-box-sizing:border-box;
    box-sizing:border-box;
}
.outer {
    width:70%;
    margin:0 auto;
}
.nav {
    list-style:none;
    display:table;
    width:100%;
    word-spacing:-1em;
    padding:0;
    margin:0;
}
.nav.head {
    border-bottom:16px solid #fc6;
    padding-bottom:3px;
}
.nav li {
    display:inline-block;
    word-spacing:0;
}
.nav a,
.nav b {
    display:inline-block;
    font-weight:bold;
    text-decoration:none;
    border:1px solid #854;
    padding:.1875em .4375em;
    margin-left:-1px;
}
.nav a:link,.nav a:visited {color:#854;}
.nav a:hover {background-color:#fcc;}
.nav a:active {background-color:#f77;}
.nav b {
    display:none;
    color:#fff;
    background-color:#f00;
}
#home .home a,
#products .products a,
#orders .orders a,
#aboutus .aboutus a {
    display:none;
}
#home .home b,
#products .products b,
#orders .orders b,
#aboutus .aboutus b {
    display:inline-block;
}

    </style>
</head>
<body id="products">

<div class="outer">
    <ul class="nav head">
        <li class="home"><a href="index.htm">Home</a><b>Home</b></li>
        <li class="products"><a href="products.htm">Products</a><b>Products</b></li>
        <li class="orders"><a href="orders.htm">Orders</a><b>Orders</b></li>
        <li class="aboutus"><a href="aboutus.htm">About Us</a><b>About Us</b></li>
    </ul>
</div>

</body>
</html>

I would like to hear about other ways of disabling the current page button without using JavaScript.
Please consider this an invitation to post your favorite(s). :slight_smile:

Hi Ron,

Thanks for the interesting post :).

Semantically the duplicate content in your example is less than perfect but from a usability point of view it would be ok as it enhances the users experience. Sometimes semantics just have to be bent out of the way a little to make things work for the best .:slight_smile:

One method I have used in the past is to use :after to shim a blank space over the top of the current link to stop it being clicked.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>No Clickable link on current item</title>
<style type="text/css">
ul#nav {
	list-style:none;
	margin:10px;
	padding:0;
	float:left
}
ul#nav li {
	float:left;
	border:1px solid #000;
	margin-left:-1px;
	position:relative;
}
ul#nav a {
	float:left;
	width:5em;
	height:2em;
	line-height:2em;
	text-decoration:none;
	text-align:center;
	background:#ffc;
	color:#000;
}
ul#nav a:hover,
ul#nav a:focus,
ul#nav li.current a {
	color:#fff;
	background:#f00;
}
ul#nav li.current:after {
	position:absolute;
	display:block;/* safari bug*/
	content:" ";
	left:0;
	top:0;
	right:0;
	bottom:0;
	z-index:999;
}
ul#nav li.current a { cursor:default }
</style>
</head>
<body>
<ul id="nav">
		<li class="current"><a href="page1.htm">Link 1</a></li>
		<li><a href="page2.htm">Link 2</a></li>
		<li><a href="page3.htm">Link 3</a></li>
		<li><a href="page4.htm">Link 4</a></li>
		<li><a href="page5.htm">Link 5</a></li>
		<li><a href="page6.htm">Link 6</a></li>
</ul>
</body>
</html>

It works well but fails if the user tabs via the keyboard as they could still activate the current link but that would seem a small price to pay and does no real harm.

I have an even older but similar demo that shims a span over the top of the anchor to support browsers that don’t support pseudo content. It’s a pretty old demo as was made to support IE6.

Your method should avoid the user tab issue associated with the method I used.

There is another method for modern browsers using html5 and adding the link text via content in the data attribute.


<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style type="text/css">
ul#nav {
	list-style:none;
	margin:10px;
	padding:0;
	float:left
}
ul#nav li {
	float:left;
	border:1px solid #000;
	margin-left:-1px;
	position:relative;
}
ul#nav li a {
	float:left;
	width:5em;
	height:2em;
	line-height:2em;
	text-decoration:none;
	text-align:center;
	background:#ffffcc;
	color:#000;
	position:relative;
	z-index:1;
}
ul#nav li a:hover, ul#nav li a:focus {
	color:#fff;
	background:#f00;
}
#one li.one:after, #two li.two:after {
	content:attr(data-link-current);
	float:left;
	width:5em;
	height:2em;
	line-height:2em;
	text-decoration:none;
	text-align:center;
	color:#000;
	position:relative;
	z-index:99;
	color:#fff;
	background:#f00;
}
#one li.one a, #two li.two a { display:none }
</style>
</head>

<body id="two">
<h1>Current class indicated by id on the body</h1>
<h2>Page One</h2>
<ul id="nav">
		<li data-link-current="Link 1" class="one"><a href="Page1.htm">Link 1</a></li>
		<li data-link-current="Link 2" class="two"><a href="page2.htm">Link 2</a></li>
</ul>
</body>
</html>

The only issue I can see with this is that screen readers may not see any text in the current link because the anchor is display:none and the text is provided via pseudo content which I don’t think screen readers read . However maybe the fact that they don’t see anything is a bonus because you don’t want them to be able to click anything anyway so maybe it makes more sense that way.

[font=calibri]@ronpat I always cringe when I see measurements like

padding:.1875em .4375em;

Where do 3/16em and 7/16em come from? Do you mean 3px and 7px? If so, that’s what you should say! Otherwise you’re at risk of 1em not being 16px.

Personally I’ve always gone for the lazy option and just set cursor:text; along with the visual styling, so the link is still clickable but it doesn’t look like it is. I’m not aware of users having any problems from this.[/font]

Hi, Stevie D!

:lol: a little quirky, maybe, but hardly cringeworthy :slight_smile:

Had I wanted pixel dimensions, I would have specified pixels. I want the padding to scale to the user’s font size.

I DO tend to use sixteenths quite a bit, but not because I expect them to be pixels. I got into this habit because I imagined that numbers that were 2^x were easier/faster for a CPU to manipulate (binary math rather than decimal). I suspect it is a meaningless consideration in today’s technology, but the pattern tends to persist. :slight_smile:

The numbers that make me cringe are the frameworks that define column widths in decimal numbers to 10-12 places. :eek: THAT’s like fingernails on a chalkboard. :lol:

Who would they call? How would you ever know?

Some users have slow connections to the internet, some pay for their service by the byte, some are on portable devices.

Some web site have pages that are very long or have lots of content including images, which translates into more server accesses, longer loading time and more bytes. Maybe it’s just me, but it seems disrespectful of users, especially those in the above listed categories, to burden them with unnecessary/unintended page reloads when it can be easily prevented.

I know this is a long-running debate, but I’m not a fan of disabling a link. I still like to be able to click the link to confirm that I’m on the right page, and also you sometimes want to refresh a page, and clicking the current link is one way to do that.

Anyhow, perhaps another modern method to throw into the right is to use pointer-events: none to disable the current link.

Given how many people are unable to read what’s in front of them but still manage to email me with stupid questions, I don’t think there’s a problem with me not being contactable in the event of a complaint :cool:

And I’ll tell you what, I’ll carry on with my streamlined code and take the hit with the occasional person who clicks on something that doesn’t look like a link, while you’re sending everyone all that extra code, and let’s see who wastes more bytes in the long run :stir:

It’s a long running debate and as I am still ‘old school’ it’s a pet annoyance of mine because it makes you feel stupid to click a link only to reload the same page! Jacob Neilsen put it plainly with regard to the behaviour of links some years ago.

A link should be a simple hypertext reference that replaces the current page with new content.

It’s simple, to the point, and in fact defines the main ethos of the web.

More specifically item 43 here:

Don’t include an active link to the homepage on the homepage. For example, if you include a “Home” link as part of your regular navigation bar, it shouldn’t be clickable on the homepage. If you use components, create a special component that is used only on the homepage with an inactive Home link. If it’s clickable, some users will inevitably click it and wonder if the page has indeed changed. Similarly, if you link your logo to the homepage from other pages on the site, the logo shouldn’t be clickable from the homepage. All other pages on the site do need a link to the homepage.

Could we do this with JavaScript?

On the current page, JavaScript would read the text between the <a> tags, then replace the <a> tags and contents with <span> tags and contents?

Most users would get the benefit of a non-clickable current page without having the extra element in HTML.

I don’t speak JavaScript or I’d give it a try.

Anyone?

This is really a question for the JS forum but here’s my attempt (which I’m sure has faults):

With Jquery:


<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style type="text/css">
ul#nav {
	list-style:none;
	margin:10px;
	padding:0;
	float:left
}
ul#nav li {
	float:left;
	border:1px solid #000;
	margin-left:-1px;
	position:relative;
}
ul#nav li a,ul#nav li span {
	float:left;
	width:5em;
	height:2em;
	line-height:2em;
	text-decoration:none;
	text-align:center;
	background:#ffffcc;
	color:#000;
	position:relative;
	z-index:1;
}
ul#nav li a:hover,ul#nav li span, ul#nav li a:focus {
	color:#fff;
	background:#f00;
}
</style>
</head>
<!-- use ids in body of one,two, three, four... etc -->
<body id="one">
<h1>Current class indicated by id on the body</h1>
<h2>Page One</h2>
<ul id="nav">
		<!-- use same ids as body but add an x to differentiate it -->
	 <li id="onex"><a href="http://www.google.com">Link 1</a></li>
		<li id="twox"><a href="http://www.yahoo.com">Link 2</a></li>
		<li id="threex"><a href="page3.htm">Link 3</a></li>
</ul>
<script src="http://code.jquery.com/jquery-latest.min.js"></script> 
<script>
	var targetID = $('body').attr('id') + "x";
	var content = $('#' + targetID).text();
	$('#' + targetID).html('<span>' + content + '</span>');
</script>
</body>
</html>

Attempt at vanilla JS :slight_smile:


<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style type="text/css">
ul#nav {
	list-style:none;
	margin:10px;
	padding:0;
	float:left
}
ul#nav li {
	float:left;
	border:1px solid #000;
	margin-left:-1px;
	position:relative;
}
ul#nav li a,ul#nav li span {
	float:left;
	width:5em;
	height:2em;
	line-height:2em;
	text-decoration:none;
	text-align:center;
	background:#ffffcc;
	color:#000;
	position:relative;
	z-index:1;
}
ul#nav li a:hover,ul#nav li span, ul#nav li a:focus {
	color:#fff;
	background:#f00;
}
</style>
</head>
<!-- use ids in body of one,two, three, four... etc -->
<body id="one">
<h1>Current class indicated by id on the body</h1>
<h2>Page One</h2>
<ul id="nav">
		<!-- use same ids as body but add an x to differentiate it -->
	 <li id="onex"><a href="http://www.google.com">Link 1</a></li>
		<li id="twox"><a href="http://www.yahoo.com">Link 2</a></li>
		<li id="threex"><a href="page3.htm">Link 3</a></li>
</ul>
<script>
	var target = document.getElementsByTagName('body')[0].getAttribute('id') + "x";
	var targetID = document.getElementById(target);
	if (document.body.innerText) {
   var content = targetID.innerText;

	} else {
   var content = targetID.innerHTML.replace(/(<([^>]+)>)/ig,"");
		}	
	targetID.innerHTML = ('<span>' + content + '</span>');
</script>
</body>
</html>



I guess another approach would be to check the href location and compare it against the destination of the href in the current item but that would involve some string splicing I guess.

Maybe @Pullo or anyone else could suggest something neater :slight_smile:

Evening all,

There are two ways that spring to mind as to how this might be accomplished using JS.

One would be like Paul has done, to use another element to determine the current page.
Two would be work out the current page by comparing the url to the href of the current item.

Both have their drawbacks.
Having to add a class to an element for purposes of navigation feels clunky, whereas the url approach can get complicated if the url is not as expected (for example, if the file is called index.html and it is not displayed as part of the url).

If I had to chose one of the two, I’d go for the first.
I’d store the current page as a data attribute, as opposed to an id.
You also don’t need jQuery to do this.

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>Disable current nav item</title>
    <style type="text/css">
      ul#nav {
        list-style:none;
        margin:10px;
        padding:0;
        float:left
      }
      ul#nav li {
        float:left;
        border:1px solid #000;
        margin-left:-1px;
        position:relative;
      }
      ul#nav li a,ul#nav li span {
        float:left;
        width:5em;
        height:2em;
        line-height:2em;
        text-decoration:none;
        text-align:center;
        background:#ffffcc;
        color:#000;
        position:relative;
        z-index:1;
      }
      ul#nav li a:hover,ul#nav li span, ul#nav li a:focus {
        color:#fff;
        background:#f00;
      }
    </style>
  </head>

  <body data-page='one'>
    <h1>Current class indicated by id on the body</h1>
    <h2>Page One</h2>
    <ul id="nav">
      <li data-item='one'><a href="http://www.google.com">Link 1</a></li>
      <li data-item='two'><a href="http://www.yahoo.com">Link 2</a></li>
      <li data-item='three'><a href="page3.htm">Link 3</a></li>
    </ul>

    <script>
      var page = document.body.dataset.page,
          nav = document.getElementById('nav'),
          items = nav.getElementsByTagName("li");

      for (var i = 0; i < items.length; ++i) {
        if (items[i].dataset.item === page){
          var span = document.createElement('span'),
              link = items[i].firstChild;
          span.innerHTML = link.innerHTML;
          items[i].removeChild(link);
          items[i].appendChild(span);
        }
      }    
    </script>
  </body>
</html>

HTH

Thanks Pullo :slight_smile: That looks quite clean.

The dataset values can only be accessed in IE11 directly I believe (plus other modern browsers). For IE10 and under you would need to get the values via getAttribute I believe ?

Yeah, that’s correct. You gotta love IE, eh?

var page = document.body.getAttribute("data-page"),
    nav = document.getElementById('nav'),
    items = nav.getElementsByTagName("li");

for (var i = 0; i < items.length; ++i) {
  if (items[i].getAttribute("data-item") === page){
    var span = document.createElement('span'),
        link = items[i].firstChild;
    span.innerHTML = link.innerHTML;
    items[i].removeChild(link);
    items[i].appendChild(span);
  }
}