本文来源于网页设计爱好者web开发社区http://www.html.org.cn收集整理,欢迎访问。implementing cross-browser compatible smart navigation features
by damon armstrong
rating:
smartnavigation is a feature built into asp.net that makes postbackssmoother by remembering the page scroll position, retaining elementfocus, reducing screen flicker, and not registering the postback in thebrowser?s history. this greatly enhances the user experience for pagesthat make use of postbacks, but it only works in internet explorer 5.5and up. in this article damon armstrong will discuss how to buildsimilar page position and focus tracking features, but which will workin all modern, standards compliant browsers.
introduction
on a recent project for a government client i was tasked with creating a user information page that needed to identify the region and office in which an individual worked. there were around 3,000 total offices, so i ended up creating two drop down lists to help narrow down the selection. the first drop down contained a list of all of the regions, and the second was automatically populated with region-specific offices by autopostbacking the form when a region was selected. because the form had a number of data entry fields, these drop down lists were located near the bottom of the form and required viewers to scroll down to see them. it worked well in internet explorer. the trouble was, it only worked in internet explorer and some of our users had other browsers.
inevitably, slightly irritated people began calling in and complaining that when they selected a region they were returned to the top of the page after the postback. this meant they had to scroll all the way back down the page to select an item from the office drop down list, and it was a bit irksome. they wanted the page to stay in the same place and maintain the tab position so they could just tab over to the office drop down. they wanted the smart navigation features that would have been available had they been using internet explorer.
my first inclination was to tell them download internet explorer because it would make all of their problems go away without much effort on my part, but i had a feeling that wouldnt go down very well. people who used browsers other than internet explorer are comfortable with and partial to their browsers, so why should they have to change? instead, i decided it would be better to build something that would mimic the asp.net smart navigation functionality but which would be compatible with the most recent versions of navigator, opera, and firefox.
this article is going to cover how to go about implementing some of the smart navigation functionality found in asp.net using cross-browser compatible javascript. it will also wrap all of the code into an easy to reuse assembly so you can import it into whatever projects you so choose without having to do a lot of reworking.
to understand this article you should have a good understanding of javascript, as well as the page scripting model. if you have never heard of the page.registerclientscriptblock() method then you should check out the links section of this article and do some catching up before pressing onward.
i'll be discussing, in some detail, how all the code works. but i know there are those of you out there who wont really want to get into it that deep into the underlying mechanism, but would just prefer to use the code. i sympathize with you, so if you are one of these people then you should read the "using smartnav on a page" section. for those of you that want a more in depth understanding, i'll be discussing what smart navigation is, how it works, and getting into the details of how to implement our own version of the features with cross-browser compatible code.
system requirements
to run the code for this sample you should have
a web server running on windows 2000 or later the .net framework version 1.1 vs.net 2003installing and compiling the sample code
full instructions for installing the sample code are contained in the readme.txt file that comes with the download. to make the sample easier to install, i've provided an installer file, smartnavsetup.msi this will launch a setup program that will create the appropriate iis entries and a smartnavdemo virtual directory and copy the sample application there. there is one step that the installation routine doesn't do, which you must therefore do by hand: you will need to copy the webtools.js file from [webroot]/ smartnavdemo/webtools/clientscript to [webroot]/aspnet_client/webtools . the aspnet_client directory is a central location where web applications for your site can find client-side script files, and the code in the sample application expects the file to be in this location. the sample won't work correctly if you don't carry out this step . there is a batch file called deploy.bat that can automatically create the necessary directory structure and copy the webtools.js file into the appropriate location if your webroot is located in c:/inetpub/wwwroot .
i have also included a copy of the demo application for xcopy deployment if you have any issues with the setup file.
running the sample application
if you run the sample application's default.aspx page, you'll see a menu with various links to other pages, as shown in figure 1. this page gives a pretty good explanation of the purposes of the other pages so i'll let figure 1 speak for itself:
figure 1. the sample application, on startup.
other than the browser information page, any of the links will get to to an identical-looking form. the contents of this form are not important it simply contains a sufficiently large number of controls that you may have to scroll down to see them all, as shown in figure figure 2.
figure 2. the large form in the sample application.
some of the controls have auto-postback enabled, and there's a submit button to submit the entire form. no action is taken when you submit the form; the interest in this article is that, with the smart navigation that i will code up, the form will be able to remember its scroll position and which control has the focus when you post back, in any modern browser.
what is smart navigation?
smart navigation is a feature of asp.net that makes post backs from web forms a bit more user friendly. it accomplishes a couple of key tasks such as maintaining scroll position, element focus, reducing screen flicker, and not registering the redisplayed page in the browsers history. the functionality, however, is highly dependent on internet explorer specific features and it does not work across all browsers. you can take a look at the smart navigation code by opening the smartnav.js client-side script file located in the /aspnet_client/system_web/[version]/ folder, but be warned that it is a very advanced piece of code. don't edit it.
whenever a page has smart navigation enabled, the page will be output with a hidden iframe and a reference to the smartnav.js file. the client-script then registers functions that allow the iframe to respond to events that occur on the web form, such as when the page loads or is submitted.
the general idea behind smart navigation is that the hidden iframe is responsible for a lot of the page processing. when the user submits the web form, the iframe gathers all the form data and sends it to the server for processing. it also determines which element currently has the focus, and saves this information for later use. the html response from the server is then received by the iframe, which then writes that html out to the actual web form once it has been completely received.
this accomplishes two things. first, it reduces flicker. normally, a page is cleared completely before new content is displayed, causing a completely white page to be shown briefly before the new content is presented. if the content of the submitted page and the new page is similar, the page just appears to flicker. when the iframe writes html back to the web form, however, the output is displayed without clearing all the contents of the page. there is no momentary flash of white, so flicker is therefore reduced. second, it maintains scroll position. since the web form never actually submits, the page position never gets reset. when the iframe rewrites the web form using the html response from the server, the web form will still be in its original location because it never moved.
client-script from the smartnav.js file is also responsible for resetting the element focus after loading the html into the web form, and for ensuring that history is not saved for post backs. by avoiding an entry into the browser history during post backs, smart navigation helps avoid issues with users clicking the back button and being presented with a dialog box asking them if they want to resubmit their form data. considering that there could be many postbacks from a single page, this is a very useful feature.
nothing is perfect, however, and smart navigation is no exception. there will be times when using smart navigation wont work or causes bugs to pop up. and, as mentioned before, it doesnt work in all browsers, which tends to exclude its use on major public websites. but its a great option for an intranet application where all of your users are on internet explorer.
in our implementation of cross-browser compatible smart navigation features we are going to focus on retaining page position and element focus. page flicker is a minor annoyance that is rapidly decreasing with processor speed, and the history issue can be lessened with appropriate navigation options. if you give people obvious navigation routes then they may be less inclined to use the back button, although because many people are so accustomed to the ease of the back button, you're unlikely to completely prevent users from using it. hence you should still take care to ensure that your code can cope with an accidental resubmission and behaves sensibly if that happens.
smartnavigation implementation overview
in this section i'll go over what the implementation of the sample code looks like, so you can see how the various projects and files fit in.
solution architecture
the demo application itself is fairly straightforward. there are two projects in the vs. net solution: the web application, and the assembly that contains the smart navigation features.
the web application contains the following pages:
default.aspxorganizational page displaying links and descriptions of other pages. nosmartnav.aspx webform with microsofts smart navigation disabled. smartnavie.aspx webform with microsofts smart navigation enabled. smartnavjavascript.aspx webform using our implementation of the cross-browser compatible smart navigation features. browserinfo.aspx shows browser information using the request.browser object, and the window.navigator.appname property in javascript.
you can open these pages up in various browsers to see the different behaviors in each. you should notice when smart navigation is enabled that internet explorer will stay in the same position when a postback occurs. in other browsers, the page will return to the top left. you should also notice that the request.browser object correctly identifies the browser types, but that opera and firefox identify themselves as internet explorer and netscape (respectively) from the window.navigator.appname property in javascript.
the webtools project wraps the javascript smart navigation features into an easily reusable assembly. there are two classes
scripting.vbcontains methods for dopostback hijacking smartnav.vb contains methods for javascript smart navigation
this assembly assembly contains the.net code that allows you to enable page position and focus tracking from a web form. it is encapsulated in an assembly for easy reuse across multiple projects.
the webtools assembly also contains the client-side script file named webtools.js that should be deployed to the /aspnet_client/webtools folder , as mentioned earlier. it contains static methods to assist with the page position and focus tracking features, and it is included on each page in which you want to use the functionality we will be implementing. note that any changes you make to the webtools.js file included in the project will not take effect until those changes are copied to the /aspnet_client/webtools folder.
figure 3 shows the overall file structure of the applciation.
p>figure 3. overview and file structure of the sample appliation
pages in your asp.net application make use of the webtools assembly by calling the webtools.smartnav.enable() method. calling this method will output the necessary javascript on the page sent to the browser so the page position and focus information will be tracked. it also make sure the right javascript include information is sent to the browser so the browser will reference the webtools.js script file.
i'll now quickly review the individual parts of the application in more detail.
webtools.js
the bulk of the javascript used for the smart navigation is encapsulated in the webtools.js client-side script file. placing this code in a client-side script file allows browsers to cache the document, thus saving bandwidth in the long run. additionally, the webtools.js file is located in a directory from which all of your web applications can access it. this allows multiple applications for a site to reference the same client-side script file and provides a single location that you need to update if changes are required to the script.
you will see code in the smartnav class registering client-side script for page execution that makes use of the functions located in the webtools.js file.
scripting.vb
this file contains a workaround for a behavioral issue with the page.registeronsubmitstatement() method. this issue and workaround were documented in a recently published asp today article i wrote, dopostback hijacking so i will not cover it in detail in this article. if you would like a full understanding of the issue, a link to this article is provided in the links section, but you can get by with what we talk about here if you so choose.
the javascript methods required to implement dopostback hijacking and the workaround mentioned above are located at the end of the webtools.js file. you will see code in the scripting class registering client-side script for page execution that makes use of those functions.
smartnav.vb
the smartnav class contains the code for registering client-side script on a page that will setup scroll position and tab location tracking. methods from this class will be called from a web form (.aspx page) to enable javascript smart navigation.
the process works like this:
the page will call the smartnav.enable() method. three hidden form variables will be added to the page. __lasttab will hold the last known tab position. __leftpos will hold the x (horizontal) scroll position. __toppos will hold the y (vertical) scroll position smartnav.enable() will register the webtools.js client-side file on the page. this ensures that the smartnav javascript functions will be available on the client. smartnav.enable() will register the required javascript functions with the page that are used to populate the three hidden variables when the page closes. if a postback occurs, the smartnav.enable() method will read the hidden variables and register javascript functions for execution when the page loads. these functions will return the page to the proper scroll position and setup the appropriate tab location.the web forms (.aspx pages)
the web forms need to call smartnav.enable() to setup javascript smart navigation. javascript functions will be registered on the page through that function, then output the browser when the page renders.
the browser is where everything comes together and executes. the browser will pull down the webtools.js client-side script file and execute javascript functions on the page to save page location and tab position before each form submission. the browser will then send these items back to the web form for processing via the hidden form variables.
the client-side javascript
all of the client-side functions needed to implement javascript smart navigation are located in the webtools.js client-side script file. as mentioned earlier, this file is located in the aspnet_client subdirectory of the webroot in a directory called webtools . the aspnet_client directory is created when asp.net is installed to hold client-side include files that are available to multiple applications. if you drill down through the directory structure, you will find all of asp.nets validation routines and internet explorer specific smart navigation files. microsoft recommends that you place your non-application specific include files in this directory because it is a central repository for client-script files for a site.
there are five main functions that i'll be discussing in the webtools.js client-side script file that deal specifically with javascript smart navigation: setfocus() , savetabpos() , setuptracktab() , setscrollpos() , and getscrollpos() . there are three additional functions that pertain to dopostback hijacking. dopostback hijacking is a technique that replaces the dopostback() function written to a page by asp.net with another function written by a developer. dopostback hijacking is used to implementing a workaround for the behavioral issues in the page.registeronsubmitstatement() method. i won't cover those functions because they are outlined in detail in my earlier article on dopostback hijacking. a link to the article is provided in the links section.
the setfocus() function
when the page is loaded, we need to be able to set the focus to a particular page element. the setfocus function accomplishes this task for us. the code for the setfocus function is shown below:
function setfocus(elementid){
if(document.getelementbyid){
//getelementbyid is supported, so use it
if(document.getelementbyid(elementid)){
document.getelementbyid(elementid).focus();
}
}else{
if(document.getelementsbyname){
var items = document.getelementsbyname(elementid);
if(items.length > 0){
items[0].focus();
}
}
}
}//end function
this function takes a single parameter called elementid that defines the html element that should receive the focus. notice that the first if statement is used to determine whether or not the browser supports the getelementbyid function. if so, then we determine whether or not the elementid references a valid element on the page on the page. if it does, we call the focus function of that element. at the time of writing, ie, firefox, and opera all support the getelementbyid() function. netscape, however, does not.
if someone is using the netscape browser then we must use the document.getelementsbyname() function to locate the item that is to receive the focus. the document.getelementbyname() function returns an array, so we create a variable to hold all of the return values. if the length is greater than zero, we assume the first item in the array is the item for which we are looking and call its focus() method to set the focus to the element.
the savetabpos() function
we can set the tab position, but we also need to be able to save it when the page is submitted. the savetabpos() function is used for this. when the smartnav.enable() method is called, it will save the element id of the active element in a hidden form variable named __lasttab the code for this function is shown below:
function savetabpos(formname){
if(document.forms[formname]){
if(document.forms[formname].__lasttab){
document.forms[formname].__lasttab.value =
document.activeelement.name;
}//end if
}//end if
return true
}//end function
the savetabpos() function is passed the name of the form that contains the __lasttab variable. it checks to ensure a form object can be located with the given formname , that the __lasttab variable can be located with that form object, and if so it then sets the __lasttab variable to the name of activeelement in the document .
the setuptracktab() function
internet explorer and opera let us know what element currently has the focus via the document.activeelement property. netscape and firefox do not have a corresponding property to let us know this information, so we have to setup a mechanism to determine this on our own.
heres the plan. if the browser identifies itself as netscape, which both netscape and firefox do, then we are going to iterate through each one of the elements looking for items that have a focus() method. the objective of us saving the element name is to call the focus() method on the element later on when the page refreshes. thus, if the item does not have the focus method then we can ignore the element.
if the item does have the focus() method, then we need alter its onfocus property. remember that the onfocus property is a javascript string that will be executed when the item comes into focus. we want the following javascript to execute whenever an item comes into focus:
document.activeelement = this;
this will effectively set the document.activeelement property in netscape to the item that currently has the focus. the code to accomplish this task is outlined below.
function setuptracktab(){
if (window.navigator.appname.tolowercase().indexof("netscape") > -1) {
var allelements = document.body.getelementsbytagname('*');
for (var i = 0; i<allelements.length; i++) {
if(allelements[i].focus != undefined){
var functionbody = 'document.activeelement = this;';
var oldonfocus = allelements[i].getattribute('onfocus');
if (oldonfocus) functionbody += oldonfocus;
allelements[i].onfocus = new function (
'event', functionbody);
}//end if
}//end for
}//end if
}//end function
the first if statement determines whether the browser identifies itself as netscape. opera will identify itself as internet explorer, and opera supports the activeelement property. so, for opera and internet explorer we do not have to do anything in this function. if the browser is netscape or firefox, then we need to setup our own activeelement property so tab tracking will function appropriately.
once we are in the main if statement, we setup a variable named allelements that will contain an array of all the elements on the page. using a for loop, we iterate through all of the elements on the page. the if statement inside of the for loop determines whether or not the item has a focus() method. if the element has a focus() method, we will alter its onfocus property. if there is not onfocus property, we disregard the item because we are only interested in elements that can receive the focus.
it is perfectly reasonable to expect the onfocus property to already have javascript in it, so we have to take that into account when modifying it. first, we create a variable named functionbody that contains the javascript we want executed to setup our activeelement property. then, we get the javascript that is currently in the element and place that into a variable named oldonfocus . if any javascript is contained in oldonfocus , then we add it to the end of functionbody . this allows our code to execute first, and then the code that was there previously to execute next. finally, we create a new function object with the code contained in functionbody and assign it to the onfocus property of the element.
although it was fairly troublesome, this will effectively mimic the activeelement property of the document object found in internet explorer. now that weve covered all of the functions required to track the tab position, lets move right into tracking the scroll position.
the getscrollpos() function
we need the ability to acquire the scroll position before the page is submitted for a postback, and this is the method that accomplishes that task. following is the code for the getscrollpos() function:
function getscrollpos(formname){
if(document.forms[formname]){
if(document.forms[formname].__leftpos){
document.forms[formname].__leftpos.value =
document.body.scrollleft;
document.forms[formname].__toppos.value = document.body.scrolltop;
}
}
}
this function is passed the name of the form that contains the __leftpos and __rightpos hidden form variables. the first line of code checks to make sure that the formname references a valid form on the page. the next line checks to make sure that the __leftpos hidden form variable is defined. if so, we assume that __toppos is also defined and we set the values to the scrollleft and scrolltop properties of the document . body object, respectively. all modern standards compliant browsers support the document.body.scrollleft , and document.body.scrolltop properties, so we do not have to do any special checking here.
the setscrollpos function
we also need the ability to set the scroll position of the browser when the page is loaded. this is accomplished from the setscrollpos() function. following is the code for the function. like the getscrollpos() function, it is relatively simple because firefox, opera, netscape, and interenet explorer all support the same scroll position properties.
function setscrollpos(leftpos,toppos){
try{
document.body.scrollleft = leftpos;
document.body.scrolltop = toppos;
catch(ex){
lastexceptionlocation = 'setscrollpos';
lastexception = ex;
}
}
this function is given two parameters: leftpos and toppos . the leftpos parameter contains the horizontal scroll position and the value of this parameter is passed into the document.body.scrollleft property. the toppos parameter contains the vertical scroll position and its value is passed into the document.body.scrolltop property.
the server-side scripting class
the scripting class, defined in scripting.vb, contains three methods that we will be using from within the smartnav class. the first method is called registerclientscript() and it is used to ensure webtools.js will be included in the page by registering the following javascript:
<script language="javascript" src="/aspnet_client/webtools/webtools.js"
</script>
next, there is a function called locateserverform() . this function is responsible for returning the name of the server from used by an asp.net page. it iterates through all of the elements on the page until it locates an htmlform object and returns its id property. this function is used to pass in the appropriate form name to the savetabpos() and getscrollposition() client-side functions in webtools.js ,
the last method is called hijackdopostback() . this method is used to ensure javascript registered to execute when the page submits will do so correctly. there is a similar method named registeronsubmitstatement() that belongs to the page object, but this method will not execute the specified javascript when the page submits using a __dopostback call. for our scroll and tab position saving functions to work correctly, the page needs to execute the specified javascript when the page submits using a __dopostback() call. thus, we will be using the hijackdopostback() method to ensure our javascript code is executed as needed. note that i've not used the onscroll event because this is not supported in netscape.
once again, the scripting class and associated javascript functions for implementing the hijackdopostback() method are outlined in detail in my dopostback hijacking article.
the server-side smartnav class
the smartnav class is what you will be interacting with directly when you are coding on a page. it contains three shared functions that will help setup smart navigation on a page.
the setfocus() method
setfocus allows you to set an initial element that should receive the focus as well track the tab position between postbacks. you will notice that it takes two parameters. the first parameter is a reference to the page on which you are trying to setup tab position tracking. initialelement is a string containing the element id of the element that should have the initial focus. following is the complete listing of code for the method:
'***************************************************************
public shared sub setfocus(byref page as system.web.ui.page,
byval initialelement as string)
dim lasttab = page.request.form("__lasttab")
if lasttab = string.empty then lasttab = initialelement
page.registerhiddenfield("__lasttab", "")
page.registerstartupscript("setuptracktab", _
"<script language=""javascript"">setuptracktab();</script>")
scripting.registeronsubmitstatement(page, "savetabpos", "savetabpos();")
page.registerstartupscript("setinittab", _
"<script language=""javascript"">setfocus('" & lasttab & "');</script>")
end sub
the first line attempts to read the value from the __lasttab form variable into a variable called lasttab . if the page has not posted back, then lasttab will end up blank. otherwise it will contain the element id set from the savetabpos function defined in the webtools.js file. if lasttab ends up blank, the next line will set it to the initialelement value. this ensures that the default form element on the page will have the focus instead of the navigation bar or some other browser element. if you do not want a default form element to receive the focus, then leave the initialelement blank.
next, the page will register the hidden field named __lasttab . this makes sure there is a form variable into which we can save the tab position from the savetabpos function in webtools.js . not to mention that we just accessed the __lasttab form variable two lines ago.
after that, the page will register a startup script to execute the setuptracktab javascript function when the page loads. remember that the setuptracktab function is defined in the webtools.js include file and is required to setup the document.activeelement property in netscape.
then we use the scripting.registeronsubmitstatement() method to ensure that the savetabpos() method will be executed whenever the page submits. this will save the active element name in the __lasttab form variable so this function read it.
finally, we register a startup script to set the initial tab focus using the setfocus() javascript function defined in webtools.js . this will ensure that the last tab position or the initial element will have the focus when the page finishes loading.
the trackpos() method
trackpos() is used to setup the page to allow for scroll position tracking. it only takes a single parameter, a reference to the page on which you want to setup the scroll position tracking. lets take a look at the code:
'***************************************************************
public shared sub trackpos(byref page as system.web.ui.page)
dim toppos as integer = 0
dim leftpos as integer = 0
if page.ispostback then
if isnumeric(page.request.form("__leftpos")) then _
leftpos = cint(page.request.form("__leftpos"))
if isnumeric(page.request.form("__toppos")) then _
toppos = cint(page.request.form("__toppos"))
end if
page.registerhiddenfield("__leftpos", leftpos)
page.registerhiddenfield("__toppos", toppos)
page.registerstartupscript("trackxy",
"<script language=""javascript"">setscrollpos(" & _
leftpos & "," & toppos & ");</script>")
scripting.registeronsubmitstatement(page, _
"getscrollpos", "getscrollpos();")
end sub
first, we define two variables, toppos and leftpos , to hold the top and left position information. if this is a postback, then we attempt to acquire the __leftpos and __toppos form variables. if they are acquired successfully they are assigned to the toppos and leftpos variables in our function.
next, the trackpos() method will ensure that the hidden form variables __leftpos and __toppos are created on the page. this ensures that the getscrollpos() javascript function defined in webtools.js has a location to which it can save the scroll position information.
then we register a startup script that will call the setscrollpos() javascript function when the page loads. this will make the page return to the proper location if it is a postback.
finally, we use the scripting.registeronsubmitstatement() method to ensure getscrollpos() will execute when the page is submitted. this ensures that the screen position information will be saved to the __leftpos and __toppos form variables for processing inside of this function.
the enable() method
most of the time you will want both tab and scroll position tracking to be enabled. the enable method calls both of the functions for you from a single location. it mainly exists to help reduce typing. there are two overloaded enable methods:
'***************************************************************
public shared sub enable(byref page as system.web.ui.page,
byval initialelement as string)
setfocus(page, initialelement)
trackpos(page)
end sub
'***************************************************************
public shared sub enable(byref page as system.web.ui.page)
enable(page, string.empty)
end sub
if you want to specify an initial element that should receive the focus, you may call the first enable method and pass in a string containing the elementid of the item that should receive the focus. if you do not want to specify an initial element, the second enable() method will automatically pass in an empty string as the initialelement .
using smartnav on a page
now that we have covered all the code, we can look at how you should use the smartnav class on a page. before you begin coding, you must have a reference to the webtools assembly from your web application. you should also reference the webtools namespace on your page with the usual imports statement in vb, or using statement in c#:
imports webtools
you can also setup the webtools assembly as a global import on the imports property page of your web application properties. this can be found by right clicking on your asp.net project and selecting properties.
with that out of the way, lets take a look at the code from the smartnavjavascript.aspx page located in the demo application. the following line of code is located in the page_load event:
smartnav.enable(me, me.txtnamefirst.uniqueid)
the first parameter of the enable method is the page on which you want to enable javascript smart navigation. you can just pass in the me reference because you are currently working from within the context of a page. the second parameter is the element id of the initial page element that should receive the focus when the page loads. in the example above, i used the uniqueid property of the txtnamefirst textbox control to get the element id. you could also type it in as a string if you so desired, or use the overloaded enable() method to avoid passing in an initial element all together.
and thats it. a single line of code inside the page_load event of your web form can enable javascript smart navigation for your users cross-browser compatible enhanced surfing experience. i would caution you against enabling both asp.nets smart navigation features and these smart navigation features at the same time. in brief testing, when both sets of functionality were enabled, the horizontal scroll position was always reset. vertical positioning and focus were retained correctly, however. there may, however, be other issues that arise when both sets of functionality are enabled that have not yet been discovered.
one thing you could do, if you want to dynamically switch between asp.nets smart navigation and our alternative, is to use the request.browser object to determine whether or not a user has internet explorer 5.5 or greater. the code would look something like this:
with request.browser
if .browser = "ie" andalso _
((.majorversion > 5) or _
(.majorversion = 5 and .minorversion >= 5)) then
page.smartnavigation = true
else
page.smartnavigation = false
webtools.smartnav.enable(me)
end if
end with
naturally, you would not want to paste this into each page you create on a website, so you would most likely want to create an inheritable page class and have this code in the load event of that class. then have all the pages in your site inherit from that base page object to include the functionality. its up to you though.
conclusion
the smart navigation feature of internet explorer makes navigating web forms much more user friendly, and now you can port that power into other browsers as well. be wary, however, to stay on your toes. as browsers are updated and newer versions of the .net framework are published, this code may need to change slightly to keep up with the times.