Update: Now there is an HTML5 history API (pushState, popState) that depreciates the functionality of HTML4 hashchange . History.js provides cross-browser compatibility and optional hashchange rollback for HTML4 browsers.
To preserve page history, the most popular and full-featured / supported way is to use hashchanges. This means that you are switching from yoursite/page.html#page1 to yoursite/page.html#page2 , you can track this change, and because we use hashes, we can pick it back and forth from the bookmarks and buttons.
You can find a great way to bind to hash changes using the jQuery history project http://www.balupton.com/projects/jquery-history
There is also a full-featured AJAX extension that makes it easy to integrate Ajax requests into your states / hashes to turn your site into a full-featured Web 2.0 application: http://www.balupton.com/projects/jquery-ajaxy
Both provide excellent documentation on their demo pages to explain what is happening and what is happening.
Here is an example using the jQuery story (taken from a demo site):
// Bind a handler for ALL hash/state changes $.History.bind(function(state){ // Update the current element to indicate which state we are now on $current.text('Our current state is: ['+state+']'); // Update the page"s title with our current state on the end document.title = document_title + ' | ' + state; }); // Bind a handler for state: apricots $.History.bind('/apricots',function(state){ // Update Menu updateMenu(state); // Show apricots tab, hide the other tabs $tabs.hide(); $apricots.stop(true,true).fadeIn(200); });
And a jQuery Ajaxy example (taken from a demo site):
'page': { selector: '.ajaxy-page', matches: /^\/pages\/?/, request: function(){ // Log what is happening window.console.debug('$.Ajaxy.configure.Controllers.page.request', [this,arguments]); // Adjust Menu $menu.children('.active').removeClass('active'); // Hide Content $content.stop(true,true).fadeOut(400); // Return true return true; }, response: function(){ // Prepare var Ajaxy = $.Ajaxy; var data = this.State.Response.data; var state = this.state; // Log what is happening window.console.debug('$.Ajaxy.configure.Controllers.page.response', [this,arguments], data, state); // Adjust Menu $menu.children(':has(a[href*="'+state+'"])').addClass('active').siblings('.active').removeClass('active'); // Show Content var Action = this; $content.html(data.content).fadeIn(400,function(){ Action.documentReady($content); }); // Return true return true;
And if you ever want to get the querystring parameters (like yoursite/page.html#page1?ab=1&a.c=2 ), you can simply use:
$.History.bind(function(state){ var params = state.queryStringToJSON();
So, check out these demo links to see them in action, as well as for all installation and usage information.