Now you have the basic navbar, we can look at adding some menus.
There are two ways to create menus:
<ul>
elements
udm-custom
file.
The most obvious reason why you might want dynamically-generated menus is if you don't use any kind of server-side or template-based includes - having all the menu data in one file reduces the amount of HTML you'd have to copy-and-paste between pages - only the top list, instead of the whole structure.
Beyond that, there are arguments on both sides:
There's a usability case for saying that only the main navbar should be available to browsers which don't support styling or have dynamic behaviors; for example, screenreaders, text-only browsers or PDAs. A large tree of links can be some effort to tab through, and is not so at-a-glance easy to comprehend.
With a very complex list-structure it might be quite intimidating, particularly if it's at the very top in a small-screen device.
On the other hand - you can mitigate the usability issue by adding headings inside the navbar list, and by putting the list HTML at the end of the source code. Or perhaps you're building an intranet where your user-base is predictable.
Hard-coded menus are also easier to maintain (providing you have some kind of includes or template system), are included in server-processes such as transient session handling, and are useful from a marketing perspective, because the menus as well as the navbar will be accessible to search-engine robots and generate click-through information in statistical packages.
You can also have a combination of hard-coded and dynamically-generated menus. Combinations are no problem, as we'll see:
The simplest configuration, hard-coded menus are simply nested
lists inside the navbar list-items. Please keep an eye
on well-formedness - nested lists go before a
closing </li>
not after it:
<li><a href="/menu/">About us</a>
<ul>
<li><a href="/products/">Products</a></li>
<li><a href="/services/">Services</a></li>
</ul>
</li>
There's no limit to how many nested levels you can have,
and no need to be concerned about their visibility either,
providing you use
menu repositioning; however there is a
certain amount of drag inherent in enormous structures -
each link is processed onload
to bind event handlers
to it, so if you have dozens and dozens of menus, the script
will begin to slow down.
It's also a good idea to avoid building child menus where every single item has a further child menu, to prevent a potentially confusing situation for people who are navigating with the keyboard. If it's viewed in a small window and those menus are dynamically repositioned, a menu which opened on the right will now open on the left, and so the left/right keys are mapped accordingly. If they're all repositioned to the left, in a menu which itself opened on the right, how do you get back to the parent? You can of course - the keys are mapped, so pressing the right-key moves left - but that's confusing, and better to avoid if possible.
If we ensure that each menu has at least one link which doesn't itself have a child menu, a user can always navigate down to that, from which the left-key predictably moves back to it's parent.
Dynamically-generated menus won't work within XHTML served as XML. However there are two extensions available which offer compatible functionality: The Load XML extension allows you to use an external XML document as your menu data source, while the Import HTML extension allows you to use an embedded HTML document.
Dynamically-generated menus are the same
HTML, but instead
of being hard-coded to the page, they're kept inside
arrays in your udm-custom
file, and
written into the navbar at load-time using innerHTML
.
They're supported with both client-side and server-side configurations, and in all cases result in menus which are generated with javascript - dynamic menus in server-side configs are not generated as pure HTML - to do so would defeat the point.
For each menu you want to create, code
a <ul>
and then turn it into a string,
which you add to a name-indexed array
called um.menuCode
(or $um['menuCode']
in PHP).
Here's an example:
um.menuCode['about'] = ''
+ '<ul>'
+ '<li><a href="/products/">Products</a></li>'
+ '<li><a href="/services/">Services</a></li>'
+ '</ul>';
PHP
$um['menuCode']['about'] = ''
. '<ul>'
. '<li><a href="/products/">Products</a></li>'
. '<li><a href="/services/">Services</a></li>'
. '</ul>';
um.menuCode['about'] = '<ul><li><a href="/products/">Products</a></li><li><a href="/services/">Services</a></li></ul>';
PHP
$um['menuCode']['about'] = '<ul><li><a href="/products/">Products</a></li><li><a href="/services/">Services</a></li></ul>';
um.menuCode['about'] = '<ul>';
um.menuCode['about'] += '<li><a href="/products/">Products</a></li>';
um.menuCode['about'] += '<li><a href="/services/">Services</a></li>';
um.menuCode['about'] += '</ul>';
PHP
$um['menuCode']['about'] = '<ul>';
$um['menuCode']['about'] .= '<li><a href="/products/">Products</a></li>';
$um['menuCode']['about'] .= '<li><a href="/services/">Services</a></li>';
$um['menuCode']['about'] .= '</ul>';
The actual name is up to you -
it relates to the id
of the list-item
you want the menu attached to. So to attach
this menu to the "About" link in our main navbar, we
simply give that list-item the same id
:
<li id="about"><a href="/menu/">About</a>
A menu string can also contain more than one menu - it can contain multiple nested levels within a single string, and providing the code is well-formed, the entire branch will be attached and work as expected. Have a look at the dynamically created menus demo for examples of this in action.
If you're using the client-side javascript configuration, single-quote characters in link-text must be escaped:
um.menuCode['about'] += '<li><a href="#jim">Jim "one-eye" O\'Reilly</a>';
$um['menuCode']['about'] .= '<li><a href="#jim">Jim \\"one-eye\\" O\\\'Reilly</a>';
Whatever method you use for creating menus, some browsers will never be able to see them; this includes partially-supported browsers such as Opera 5 and 6, and any fully-supported browser with CSS on but javascript disabled. So you need to provide duplicate links for submenu content - anything which is accessible from the menus must also be accessible without them, as documented in The need for duplicate menu links.
For browser-based screenreaders, whether or not they can access the menus is entirely unrelated to which menu creation method you use, because browser-based readers can access script-generated content just the same; providing, of course, that javascript is enabled, and that the content is displayed, visible, and needs no user-action to make it so. But that is the case with this script - the menus are initially hidden using offleft-positioning, rather than display or visibility.
But not all screenreaders are browser based - pwWebspeak is an example of one that isn't; it doesn't support scripting or CSS at all, and is therefore equivalent to a text-browser - it can only see hard-coded menus.
Dynamically-generated menus won't work within
XHTML served as XML, because they're appended
using innerHTML
. However there are two
extensions available which offer compatible functionality:
UDM 4 is valid XHTML, and in our judgement, meets the criteria for WAI Triple-A conformance.