Cross-Browser Fixed Horizontal Bar (no frames)
Charles Roth 2004-02-17 (Skip to the solution.) I. Introduction
I want to have a single HTML page that has "fixed" control and display elements: buttons, menus, status bars, etc. that will not scroll as the page scrolls. I want the capability for vertical and horizontal "bars" on which to put these elements.
- Frames? Oh yes, been there, done that. Ugh. The killer is the lack of bookmarking, and the implied lack of permalinks into the frameset. The inter-frame communication can get pretty complicated, too, if frame X needs to update frame Y, and so forth. And let's not even talk about the Back button...
- CSS? Don't we all wish. Eric Meyer's book on Cascading Style Sheets has a perfectly lovely, simple, approach to fixed vertical and horizontal bars... but it doesn't work (at all) in IE 5 or 6.
II. Just Vertical Bars?
Even with IE's problems, these are pretty easy... see Eric Bednarz's excellent pages at devnull.tagsoup.com. Eric has a good demonstration of a horizontal bar, as well, but points out that it seriously breaks page anchors, which have a tendency to "hide" underneath the top fixed horizontal bar.And one can certainly argue that the typical PC screen is "better used" to reserve the vertical axis for scrolling content, and space on the side for control elements. After all, we read better when text is not too wide, so why "waste" vertical real estate on a fixed bar?
III. The Real Goal
Because I want it, anyway, dammit! <g> Every single installed application, including all of the browsers, have their own control elements across the top; why shouldn't a web-based application act the same way?(David Woolley pointed this out in, oh, 1996, in this article, and the state of the art hasn't improved much since.)
Here's what I really want:
- A fixed horizontal bar at the top of the page. (Adding a fixed vertical bar is an easy extension).
- A horizontal bar that dynamically resizes itself according to content (text or images or...) and browser window resizing. (I don't want to have to pick an explicit number of pixels, or percentage of screen height.)
- Anchors ("hash marks") that work. I want to be able to include an anchor in the URL and see it, or click on a link in the document, that scrolls correctly to an anchor in the same document.
- All page elements work the way the user expects. (Nothing appears or disappears in strange ways. The vertical elevator works in its normal way to scroll the page.)
- A Back button that works.
IV. The Solution
In fact, it can be done! See FHdemo to try it out.Well, with one tiny exception... using IE, the Back button does not navigate backwards properly from intra-page anchors in the same page.
But otherwise, it works in IE 5.5, IE 6.0, Mozilla 1.5, Netscape 7.02, and Safari. I welcome tests and feedback on other browsers, please send to roth@thedance.net.
V. Technical Details
There's a lot of strange work-arounds going on inside FHdemo. Here's some context that will help make sense of the code itself:
- The basics of doing the fixed positioning of the horizontal bar are straight out of Eric Bednarz's pages.
- This puts a "layer", if you will, on top of the page. Stuff scrolls underneath it. In order to have (what the user thinks of as) the top of the page not be hidden underneath, I simply duplicate the content of the horizontal bar, at the very top of the page.
This means that we don't need to know the exact size of the horizontal bar, or care if the window is resized.
- There are three DIV's with distinct classes that I use to do this. FHheader contains the top horizontal bar. FHwrapper "wraps around" the rest of the page, and contains the duplicate of the horizontal bar, plus the content. FHmain contains the content, and adjusts the margins slightly to look like a "normal" page.
- In order to keep the vertical elevator visible (all the way to the top of the window), I shift FHheader left 16 pixels under IE. This can break if the user changes the default setting for the width of the elevator, although that is extremely unlikely in practice. (There's some CSS magic in there as well, to make sure that the underlying copy of the horizontal bar is really the same width as the fixed horizontal bar.)
- Scrolling to an anchor is the really fun part. Here I defined FHscrollToCurrentHash() to:
- First scroll an anchor into view via scrollIntoView() (typically but not always at the top of the "real" page).
- Then scroll the page down some more, by the current, actual height of the horizontal bar, in pixels.
This means, unfortunately, that intra-page links will not work as normally written. They have to be modified to use a Javascript function, as in:
<a href="#v1" onClick="return FHgoToAnchor('v1');">Verse One</a>Safari note: scrollIntoView doesn't work in Safari 85, so I set a timer event in FHscrollToCurrentHash() that does step 5.2 in 200 ms, presumably after the return from the anchor click.
- IE has a nasty little bug wherein the <select> tag still "shows through" the fixed position bar. Fortunately Joe King has a work-around, that involves "shimming" an <iframe> between the main page and the fixed horizontal bar. For totally magic reasons, the invisible iframe still manages to block the appearance of the select element.
In my case, I have FHsetup (called on onLoad and onResize) re-figure the proper size for the iframe dynamically.
VI. Commercial Plug
I threw this all together so that I could have a fixed horizontal bar to use in my "Caucus" conferencing/discussion/collaboration tool. If you need such a tool, please check us out.And I'm also available as a consultant on, and developer of, interesting cross-browser web applications...
Cheers!