Not to toot my own horn, but everyone loves this site's top navigation menu. I've received more questions about how I did it than I can answer. As a result, I've decided to write a tutorial on it. Before beginning this tutorial, the reader should be somewhat familiar the following:
Also, be sure that you have installed PHP-Template, and a fresh copy of Box_Grey on hand.
Now a quick word of warning: This tutorial, and these concepts are not for the weak-willed and weak-minded. The concepts we're going to cover are inherently frustrating, difficult, and confusing. However, if you work to understand them, and make a commitment to get this right, I promise huge rewards in your overall understanding of CSS. And take it from me, a solid understanding of CSS means more than personal satisfaction, it can also make you a reasonable living.
First things first, unzip yourself a new install of box_grey, and rename the "box_grey" folder "madness". Now, let's include a seperate stylesheet for our navigation menu. Using a text editor, open up the file themes/madness/page.tpl.php. On line 8 add some code for the new stylesheet like a so:
<style type="text/css" media="all">@import "themes/madness/menu.css";</style>
Now, we are going to replace what used to be the primary and secondary links with a dynamic full user menu. Go to line 31 and delete everything within the "top-nav" DIV, and replace it with the following code:
<div id="top-nav"><?php $UserMenu = theme_menu_tree(0);print $UserMenu; ?><br class="clearnav" /></div>
By now, you should save your work and check out your site. You should see this:
Obviously, we're not done... Our menus are displaying vertically, and have those lovely box and arrow bullets. My friends, we have no choice but to bring in the CSS.
Remember in the earlier step when I told you to include the file themes/madness/menu.css? Well, we sort of forgot to create that file, so let's go ahead and do it. Hopefully, you don't need me to explain how to create a file called "menu.css" in your themes/madness directory....
Open your new file "menu.css"; it should be a completely blank file. Take a deep breath reader, your understanding of CSS is about change dramatically. Now might also be a good time to brew a pot of coffee. Now its time to go medioeval on this nested list's ass. Write your first rule:
#top-nav li {display:inline;}
So before, our menu was standing up all tall talking trash about our mothers; and we just couldn't let that stand. So we said, "Okay, stupid nested menu, say hello to my little friend!" Or, the more technical version is we told our CSS document that all lines within the top-nav div to display inline. Here is the result:
Mmmhmmm, the above menu just got served. However, as we will soon find out, our menu still thinks it can talk trash. Click a link to another layer of menus (i.e. click administer). Look at the nerve:
At first glance this looks like a nightmare. The weak will give up at this point and simply declare "it cannot be done!". However, we are strong, and we're going to crush this minor inconvience.
The reason that the new layer of menus is splitting its parent menu in half can be found at the markup level. Drupal generates new menus within menu lines like a so:
<div id="#top-nav"><ul><li>EXPANDED MENU ITEM</li> <ul> <li>MENU ITEM<li> </ul></li></ul></div>
Now that we understand how this markup works, we can bust out some CSS-kung fu. Now Grasshopper, add two more CSS rules
#top-nav li {display:inline;} #top-nav ul li ul {float:left; width:100%;}
Pay close attention to how this new CSS rule is written. Where as our first rule #top-nav li applies to all lines within the top-nav div, our new rule is much more specific. In English, it says we only apply this rule only within the #top-nav id, and to unordered lists within lines of an unorder list. Sound confusing? It is, but only because I tried to put it into english. Take a look progression in HTML code for our nested lists a few lines up, follow the elements to "MENU ITEM"; they are:(1)#topnav, (2)ul, (3)li, (4)ul. Look familiar? Perhaps now you'll begin to understand why many geeks wish we spoke code instead of english. In all cases, following the progression like this helps you apply CSS rules like a sharp shooter.
We've told #topnav ul li ul to "float:left". This slides it to the left (obviously), but more importantly, causes the new layer of lists to no longer split parent menus in half, or leave empty space. However, float also by default will causes our list to shrink to its minimum required width. So we've overrided that by specifying "width:100%". Now, look at the magnificent result:
SUPRISE! There is another problem, and this one is particularly scary looking. While the second layer of lists behaves perfectly, the third layer corrupts our entire layout, sliding to the right by no less than 1000px!
Frankly reader, we don't know, and we don't care. There is any easy solution. Add your third CSS rule and finish today's foe for good:
#top-nav li {display:inline;} #top-nav ul li ul {float:left;width:100%;}.clearnav {clear:both;}
Shazam, one shot, one kill. ".clearnav {clear:both}" was the missing link. We now have menus which will expand horizontally, without problems, into infinity. If you must know "clear" typically clears out any odd behaviors that are caused by floats. Observe our unstyled menu's beauty:
The good news is that by this point we're about a quarter of the way there. Er, wait that's the bad news, sorry. Today, we've merely created the foundation to our menus. However, I want to personally congradulate all three of you that have managed to get this far. In our next tutorial I will teach you how to style the individual levels of the menus. Specifically, we'll cover how to apply different styles for menus that are expanded, collapsed, active, or dead ends. In our third tutorial we will cover advanced styling such as shades, rounded tabs, or entirely different displays (however, I myself am still figuring out how to do that...)
As always, please let me know if you have any problems with this tutorial. I will not only be happy to help you, but most likely others are experiencing the same problems as your are. So asking for help not only helps you, but it helps anyone else who is attempting to learn these concepts.
Comments
this tutorial sucks !
it doesnt show anything. the author clearly doesnt know what he is talking about.
Can't seem to make this work
Thanks so much for this tutorial, but I've followed your instructions with box_grey and my menu items appear one on top of another. I did notice that the div in page.tpl.php in the original file did not start on line 31, but I replaced its contents according to the tutorial. Any suggestions?
Thanks!
So far so good, pretty much
Problems implementing this
Hi Nick,
Excellent tutorials!
I am using the friendselectric theme and came unstuck when simply adding the inline code to the top-nav. They just don't go inline!
When i look at source, i notice there are span classes around the list items (eg)
As you can see this is no way as simple as you example above. How can i modify the new menu created just for this, so that all that extra styling is ditched? ..and then hopefully i will have an inline menu :)
Are you generating a plain
Some results
Ok, i have removed the follwoing from the template file:
function phptemplate_wrap_links($link, $n) {$classes = array("lw1", "lw2");
$before = $after = "";
foreach ($classes as $c) {
$before .= '<span class="'. $c .'">';
$after .= '</span>';
}
$link = preg_replace('!<a[^>]*>!i', '\0'. $before, $link);
$link = preg_replace('!</a[^>]*>!i', $after . '\0', $link);
return $link;
}
function phptemplate_menu_item_link($item, $link_item) {
/* Wrapper span */
return l('<span class="lw1">'. check_plain($item['title']) .'</span>', $link_item['path'], array_key_exists('description', $item) ? array('title' => $items['description']) : array(), NULL, NULL, FALSE, TRUE);
}
The results is that the span classes are removed. However, again looking at the html source, i still have expanded and leaf ids:
<div id="top-nav">
<ul>
<li class="expanded"><a href="" title="" class="active">Top category 1</a>
<ul>
<li class="leaf"><a href="" title="">2nd level 1</a></li>
<li class="leaf"><a href="" title="">2nd level 2</a></li>
<li class="leaf"><a href="" title="">2nd level 3</a></li>
</ul>
</li>
<li class="leaf"><a href="" title="">Top category 2</a></li>
</ul>
<br class="clearnav" />
</div>
Now i have, as you have suggested, set #top-nav in my style.css. However the following code that is needed to style the menus in the sidebar also affects the top-nav lists as well:
.item-list ul li, li.expanded, li.collapsed, li.leaf {
list-style-type: none;
list-style-image: none;
margin: 0;
padding: 0px;}
.item-list ul li a, li.expanded a, li.collapsed a, li.leaf a {
margin: 0;
padding: 3px 1px 3px 5px;
display: block;}
li a.active {font-weight: bold;padding-left:15px; color: #36456c;background: url(indent1.png) no-repeat 4px 5px;}
.item-list ul li a:hover, li.expanded a:hover, li.collapsed a:hover, li.leaf a:hover{
background-color: #fff;
color: #486e98;
padding: 2px 0px 2px 4px;
border: 1px solid #ccc;
font-weight: bold;
background-position: 3px 4px;}
li a.active:hover{
background-color: #e2ecf9;
color: #36456c;
padding: 2px 0px 2px 14px;
border: 1px solid #e2ecf9;
background-position: 3px 4px;}
Please bare with me, as i am a complete css newbie, but how can i set the code above to JUST style the the menus in the sidebar?
I tried things like adding #sidebar to each of the styles above, but everytime it affected everything, not just the sidebar menus....
Tell me about it!
Short answer
ASAIK just remove the code i put above. The only major side effect is that the edit/view/track tabs when logged in collapse as their styling disappears. Would be nice if they were sorted but not in public view, so not totally bothered. :)
Anyway, by emoving that code and setting the ul/li for the side menus to #sidebar-right (or left whichever you are using) i managed to set up a great looking top nav menu. Thanks Nick!
Your menu tutorial
xtemplate.xtmpl
Lucid explanation from a
Gunny, I'm already ahead of
no need for customizing the menu.module
Thanks for the tip Michael.
Thanks for the tip Michael. However, I'm afraid this technique won't work for us. I took a look at the source code for the tabs, take a look:
<ul><li><a href="/home" class="menu"><b class="snazzy"><span class="boxcontent active">Home</span><b class="b4 darkblue"></b><b class="b3 darkblue"></b><b class="b2 darkblue"></b><b class="b1"></b></b></a></li>...</ul>While this a pure CSS solution, it is far too bulky to be a good choice (in my opinion) for a large global expanding menu that contains hundreds of links. THis is for two reasons, one the extra markup (i.e. b class) can get really messy when required to display across more than one level, two the extra markup, in our case, will likely hurt a site's search engine ratings (google hates it when lots of links are marked up like this). In addition, this solution would require customization, refer to the source code for drupal's menu items in my latest article:... as you can see, there are some pretty profound differences in the source code.
However, on a less oppositional note, this is a very odd solution, and one that I've never seen before. It works perfectly on both browsers, and I'll explore it further. My first impression was that it was unnecessarily complex -- but then again, as I keep finding out, I am a cocky idiot. Thank you, again, for pointing me to this.
Also, quick note, my spam filters have gone FUBAR thanks to an overnight attack by fringe pornographery spammers (oh the phrases they left...), so at the moment, legit comments are being unpublished. I'll be checking up on my unpublished comments through out the days, so fear not, you will have your say... it might jst not be immediate.
a bit more info
No kidding about avoiding
Post new comment