Structure your site and get a menu for free
A well structured site will in many cases give a lot of goodies for free. A good structure are good for user interaction, it's good SEO and there are bucket loads of examples where a clean and well structured site are an benefit in the back end. In this example I'll explain how a good structure can result in an menu almost for free.
As an example, an good structured can be represented with the following directory structure:
|- norway
|- bergen
|- oslo
|- denmark
|- copenhagen
|- roskilde
|- england
|- london
|- liverpool
In an URL, if we target roskilde, this should be represented with the following nice URL: http://www.sitename.com/denmark/roskilde/.
I've always looked at menus as an visual representation of how the site are structured. In my head the structure of an site, the URL to each page on the site and the sites menu should go hand in hand. Before we can give the menu a visual representation we need to deal with the markup. The most correct way to deal with the above structure would be to express it as it is trough an list element:
<ul>
<li><a href="/norway/">Norway</a>
<ul>
<li><a href="/norway/bergen/">Bergen</a></li>
<li><a href="/norway/oslo/">Oslo</a></li>
</ul>
</li>
<li><a href="/denmark/">Denmark</a>
<ul>
<li><a href="/denmark/copenhagen/">Copenhagen</a></li>
<li><a href="/denmark/roskilde/">Roskilde</a></li>
</ul>
</li>
<li><a href="/england/">England</a>
<ul>
<li><a href="/england/london/">London</a></li>
<li><a href="/england/liverpool/">Liverpool</a></li>
</ul>
</li>
</ul>
This is actually all we need in the markup to make an fully functional menu which can be visually represented in many different ways and also have different focus depending on where we are in the structure. There is no need for any CSS classes or id's telling us “iscurrent”, “issibling” etc, etc. There is no need for any JavaScript either.
The key to create an functional menu are to have something unique we can use. Since we have a well structured site, the URLs found in the “href” are more than unique to reach our goal. Said in another way; there are no duplicate URLs on the same level in the list, and this we can use to select what we want in the list.
We can do a lot of logics by combining the attribute selector and the general sibling combinator in CSS 3:
a[href="/denmark/"] ~ ul{
your style....
}
will give access to the “denmark” element and the children elements in our example structure above.
One thing which is unique for a web page is the URL to the page. If we use the URL for a page and match it with the value of the “href's” in the menu we can manipulate the menu for each page. In other words, we need to produce one unique combination of CSS selectors for each page instead of an unique markup for each page.
A real life example
Lets say we want to produce a menu which looks like this from the above structure:

The first thing we need to do is to give our menu a basic formating where the most important part is to set all the second levels (the cities) to hidden. We will then be setting the second level we want to display by setting an style to visible depending on what URL the user are on. Hiding the second levels is done by targeting descendant ul tags:
#menu ul ul{
display: none;
}
Rest of the styles giving the menu a “nice” look can be seen here.
The next step is to display the correct second levels (the cities) in the menu depending on the URL. Normally the URL to the page are easily available server side so the most convenient way to do this for would be to print an small inline style in the markup for each page.
For “Norway” in the first level it will look like this:
<style type="text/css">
#menu a[href="/norway/"] ~ ul{
display: block;
}
</style>
For “Denmark” in the first level it will look like this.
<style type="text/css">
#menu a[href="/denmark/"] ~ ul{
display: block;
}
</style>
You can see a full working example of this example here.
This works in IE7 (and newer), FireFox 3, Opera 9.x, Safari 3.x and even on Opera mini and the iPhone...
What about IE6?
Yes, I know. This does not work in IE6. Personally I would recommend to drop support for IE6. IE6 are an browser web developers should have stopped trying to fix things in ages ago. IE6 has been around way too long and one of the reasons for that is because web developers tend to make things work in IE6 on the same level as newer browser. But, this is another discussion I'm not gonna raise here.
Anyhow, if you need to support IE6 this can be done with a small JavaScript which you serve only for IE6. The reason for why this is not working in IE6 is the lack of support for the CSS3 selectors we are basing this technique on so the JavaScript will work as an replacement for those in IE6.
I've written an small JavaScript which will do the trick. This script need to traverse the DOM tree to find the “ahref” attributes which we use as unique references so you need to provide the first ul in the list with an CSS id selector of your choice so we can narrow down the search in the DOM tree to only the menu.
What we then do is to include a call to the JavaScript where we provide the URL to the level we want to target in the menu and the name of the id selector of the ul list. In a way, we use the same logic as when we let the CSS do the job.
For “Norway” in the first level it will look like this:
<!--[if lte IE 6]>
<script type="text/javascript">
menuFixIE6('http://www.yoursite.com/norway/','menuid');
</script>
<![endif]-->
For “Denmark” in the first level it will look like this.
<!--[if lte IE 6]>
<script type="text/javascript">
menuFixIE6('http://www.yoursite.com/denmark/','menuid');
</script>
<![endif]-->
By using the conditional comments for IE 6 this will not call the function for the browsers who support the CSS selectors making this technique work.
You can see a full working example of this example here.
What are the benefits of doing a menu this way?
One benefit is that visual representation are lifted 100% into the CSS layer. We could choose to do the switching of what should be visible or not with JavaScript, but CSS implementations in browsers are way faster to manipulate the DOM tree then JavaScript implementations are.
We could also choose to set different CSS classes or Id's on different levels in the list element or even choose not to print out parts of the list element for each page but this will lead to different markup which are hard to maintain in static pages and introduce complex code on the server side on dynamic pages. In other words we eliminate a lot of program code on the server side or/and reduce the amount markup needed to be maintained.
But, the biggest benefit might be found server side on dynamic websites. Many large scale websites rely on extensive use of caching on several levels. The rendering of the markup of an menu are in many cases an object suited to be cached on the server. If CSS classes or Id's must change in the markup depending on what should be displayed in the visual presentation, one will end up with as many cache objects of the menu on the server as there are visual representations of the menu. By doing all the logics in the menu client side, the server will only need one cached menu object. We still need to do some unique rendering for each page. We need to produce the CSS selector but the only thing which need to be unique in this selector is the URL to the page the user stands on. Extracting and printing the URL are much less resource intensive and require much less code in most cases.
For those of you familiar with Edge Side Includes (ESI) this could be a great benefit.
14.01.2009 12:33 - Posted by Trygve - Comments: 0 - Technical
About:
My name is Trygve Lie. I live in Oslo, Norway where I deal with web technology. You can read a bit more about me here.
Search:
Categories:
Links:
Feeds:
Tags
- atom
- blog
- components
- css
- dom
- entitys
- esi
- html
- ie6
- ie7
- ie8
- java
- javascript
- jsp
- jstl
- performance
- roller
- saxon
- scriptless
- selectors
- structure
- theme
- validation
- varnish
- webslices
- welcome
- xalan
- xhtml
- xml
- xslt
Comments: