Fixed/Absolute scrolling vertical menu

I’m very sorry to be so slow getting back with you.

Yes, I can reproduce the bug in the old demo.

To reproduce the bug in the new demo,
Open (or reload) the page in a window that is a fair bit shorter than the height of the menu, so that less than half of the disk at the top is visible. Then gradually extend the height of the window… drag the bottom down slowly. Watch for a big jump!

That last rather chopped up version back to you seems to work everywhere except when Opera reloads and the snippit that you sent should fix that… I just have not had time to try it, yet.

Calculating the box positions and/or heights is the right technique. Relying on the fixed value that I stuck in there isn’t desirable, but the calcs just aren’t working for me for some reason.

Hey guys,

I’ve just been trying to test this out on my machine to see if I can reproduce any of the results. I’m getting an odd result that may or may not help:

In Opera 12.15, if I load Pullo’s Demo 2, resize the window (so it cuts off the bottom half of the ‘Sponsors &’ button) and then refresh the page, the menu breaks. All the menu items after ‘Local sights’ run off the bottom of the page. The weird thing is, if I download the page to my machine, and run it on my local server then I don’t get the problem - the menu looks as it should.

Edit: I get the same result in FF 21

Hi fretburner,

Thank you for replying :slight_smile:

This is driving me mad …

In FF 21 on Windows 8, I opened Demo 2 (from the web, not locally).
I then resize the window, exactly as you say (so that it cuts off the bottom half of the ‘Sponsors &’ button).
Then I refresh the page.
But the menu doesn’t break. It behaves as it should.

I wonder why can’t I see what you can see?
Which OS are you using?

Morning Pullo,

I’m using Windows 7 (32 bit), although that shouldn’t affect the results I wouldn’t have thought as the version of FF should be identical for both.

I was looking for some examples on the web to see how other people get this effect with the menu, and I came across this example in the Bootstrap docs. The left menu uses the same effect, and they use their own JS module called Affix: http://twitter.github.io/bootstrap/javascript.html#affix. Maybe it would be worth trying to use/adapt this?

OK, so I have some more results to report. I’ve uploaded the 2nd demo to my own web space and it suffers the same problem as when I load it from your server, Pullo.

I also tested a small change to the JS which seems to solve the issue:

$(document).ready(function(){
    var $nav = $('.nav'),
        $page = $(document),
        $frame = $('.frame'),
        nav_height = $nav.height(),
        frameHeight = $frame.height(),
        topOffset = $frame.position().top,
        initialBottomOfNav = topOffset + nav_height,
        initialBottomOfFrame = topOffset + frameHeight;

    calcNewPosition();

    $(window).scroll(function() {
        calcNewPosition();
    });

    function calcNewPosition() {
        var newNavTop = 0,
        frameOutOfView = $page.scrollTop() -  topOffset,
        frameRemaining = frameHeight - frameOutOfView;

        if (frameRemaining <= nav_height){
            $nav.addClass("absolute");
        } else {
            $nav.removeClass("absolute");
        }
    }
});

I’d be interested to know what results you both get - here are the links:

Ver2 (Pullo’s)
Ver2b (with the above changes)

Hey fretburner,

Good stuff!!
Your demo works fine on my PC in both OPera and FF, but then again so did my original :slight_smile:

I’ll be interested to hear what Ron has to say.

Hi, fretburner, thanks very much for joining the party. I have to admit that I had no idea that such cross-browser and server-vs-local issues existed with JavaScripts. My hat’s off to you guys for being able to understand and work with these problems.

Two screen shots.

The URL is http://nilsonjacques.com/projects/scroll/demo2b.html

Note that I added a magenta outline around .nav and .frame.

Left screen shot I have scrolled to the bottom of the page. .nav is position:absolute.
Note the height of the window, the position of the bottom of .nav and .frame, and the brown disk.

Right screen shot shows the window after being extended 1px taller (same as scrolling up 1px).
Note the “jump”. .nav has become position:fixed.


As an academic exercise, there is lots of brown space on this page where the values of the functions could be displayed in a fixed box as they change. Is it possible to do that? I am trying to understand what-does-what and how they work together.

Hi Ron,

Thanks for the screenshots. These helped me to reproduce the issue - yay!

I think I’ve found the problem (although I’ve said this before in this thread).

Try this demo (number three)

Demo one is available here and demo two [URL=“http://hibbard.eu/blog/pages/fixed-absolute-scrolling-vertical-menu2.html”]here (just for the sake of comparison).

If this doesn’t fix your issue, we can work out how to output the relevant variables to the screen and have them update in real time. I think that is an excellent idea.

FWIW, I spent ages playing around with the bootstrap demo fretburner linked to.
However, I can actually break the demo (hosted on github) quite easily by doing some of the stuff we discussed here :frowning:

Let me know how you get on.

I’ve been experimenting. Went to bed when my eyes finally crossed last night. :lol:

I think I know where we have been going wrong, but I need to experiment a lot more before I’ll feel confident enough to post my findings. Then you can tweak it :).

Will get back with you after I’ve read and played some more.

Thanks for not giving up!
Ron

@Pullo and @fretburner,

Give this a run!

Changes:
(1) Added 2 variables, navTopPosFixed and navBottomPosAbs, to hold the fixed values for the top and bottom nav menu offsets.
(2) Changed from $frame to $canvas.
(3) For coding purposes, I used the “longhand” script to change the styles instead of adding and removing .absolute so I could keep the positioned values in front of my face. Both methods work equally well.
(4) Changed .nav {position:absolute;bottom:15px} to {position:absolute;bottom:25px} for asthetic reasons.
(5) Renamed some of the variables.
(6) Added “remarks” and comments help describe variables.
(7) Added script to write to “varViewer”.

Successes:
(1) Works flawlessly in IE8, IE9, FF, Chrome, & Opera.
(2) Added “varViewer”.

Room for improvement:
(1) The values for navTopPosFixed and navBottomPosAbs are applied manually. While their values may change dynamically as the page is scrolled in a short window, the fixed values are the ones that the script must retain. It looks like the longhand method of applying these values is more convenient since the numbers reside in one js file and not in both the css and js files.
(2) Maybe I’ll try to convert this to plain JavaScript as another learning exercise :slight_smile: .
(3) Criticisms & suggestions for improvement are encouraged!

I’m tickled that it works! Both of you, please accept GIANT "Thank You"s for setting up the script structure for me. I was clueless.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<!--
http://www.sitepoint.com/forums/showthread.php?1110817-Fixed-Absolute-scrolling-vertical-menu
Thread: Fixed/Absolute scrolling vertical menu
Jun 11, 2013 05:08
ronpat
-->
<head>
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
    <meta http-equiv="content-language" content="en-us">
    <meta http-equiv="content-style-type" content="text/css">
    <title>Menu eXperiments</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
    <style type="text/css">
html,
body {
    height:100%;
    padding:0px;
    margin:0px;
}
body {
    color:#000;
    font-size:100%;
    font-family:Verdana,sans-serif;
    background-color:#bdf;    /* set the background-color of the browser window here #bdf */
    overflow-y:scroll;
    padding:0;
    margin:0;
}
/* Opera Fix */
body:before {    /* thanks to Maleika (Kohoutec) */
    content:"";
    height:100%;
    float:left;
    width:0;
    margin-top:-32767px;    /* thank you Erik J - negate effect of float */
}
#outer {
    width:988px;
    min-height:100%;
    position:relative;
    margin:-50px auto 0;    /* footer height - this drags the outer 40px up through the top of the monitor */
}
.canvas {
/*    outline:1px solid magenta;  /* TEST OUTLINE */
    background-color:#532;    /* overall background-color */
    border-radius:20px;
    padding:15px 15px 15px 156px;
}
#footer {
    height:50px;
    clear:both;
}
#footer p {
    font-size:0.75em;
    font-family:'Trebuchet MS',sans-serif;
    text-align:center;
    padding-top:16px;
    margin:0;
}
/*  */
h1 {
    height:10px;
    border-top:50px solid #fff;    /* soak up negative margin and allows header to start at top of page */
    font-size:.6em;
    text-align:center;
    visibility:hidden;
    margin:0;
}
/*  */
/* PAGE BORDER & SIZE DIVs */
.content {
    background-color:#e9e8e4;
    background-image:url('../imgs/newsprint1.jpg');
    background-repeat:repeat;
    background-attachment:scroll;
    border-radius:12px;
    width:769px;          /* 817px wide */
    min-height:600px;
    padding:12px 24px 18px;
}
.frame {
    position:relative;    /* just in case you want to p:a something over the image */
}
#p .frame {
    position:static;      /* permits the menu tab to overlay the border around the poster image */
}
.frame img {
    display:block;
    border-radius:12px;
}

/* Navigation  ( screen: height >= 590px; width >= 988px ) */
.nav {
    list-style-type:none;
    position:fixed;
    left:50%;
    top:22px;              /* auto */
    bottom:auto;           /* 15px */
    padding:0;
    margin:0 0 0 -484px;
}
.nav.absolute {
    position:absolute;
    top:auto;
    bottom:25px;        /* absolute (relative to #outer) */
}
.nav li {
    display:block;
    width:138px;
    text-align:center;
    font-weight:bold;
    font-size:18px;
    font-family:Verdana,sans-serif;
    padding:0;
    margin:0;
}
.nav li + li {
    margin-top:8px;
}
.nav li.urhere,
.nav li.dummy {
    padding:8px 0;
    width:134px;
}
.nav li.urhere {
    border-top:2px solid #ffd700;
    border-bottom:2px solid #ffd700;
    border-left:2px solid #ffd700;
    border-radius:10px 0 0 10px;
    background-color:#fff;
    color:#000;
    padding-right:10px;
}
.nav li.dummy {
    border:2px solid #865;
    border-radius:9px;
    background-color:#421;
    color:#865;
}
.nav li.p {
    margin-top:12px;
}
.nav li.a.urhere,
.nav li.c.urhere,
.nav li.f.urhere,
.nav li.l.urhere,
.nav li.r.urhere,
.nav li.s.urhere {
    background-color:#e9e8e4;
    background-image:url('../imgs/newsprint1.jpg');
    background-repeat:repeat;
    background-attachment:scroll;
}
.nav li.p.urhere {
    background-color:#88c4e6;
    position:relative;
}
.nav li.p.urhere:after {
    content:"";
    width:4px;
    position:absolute;
    top:0;
    right:-4px;
    bottom:0;
    background-color:#88c4e6;
}
.nav li.i a {
    display:table;
    border:0;
    border-radius:50%;
    padding:2px;
    margin:0 auto;
}
.nav li.i a:active {
    background-color:#f00;
}
.nav a {
    display:block;
    border:2px solid #865;
    border-radius:10px;
    background-color:#421;
    color:#f0f0f0;
    text-decoration:none;
    padding:8px 0;
}
.nav a:link,a:visited {}
.nav a:hover {
    color:#00f;
    border:2px solid #00f;
    background-color:#ccc;
}
.nav a:active {
    color:#f00;
    border:2px solid #f00;
    background-color:#eee;
}
.nav a img {
    display:block;
    border:none;
}

/* IMAGES */
.rogposter {
    border:4px solid #ddb600;    /* #ddb600 */
}

/* varViewer */
.varViewer {
    min-width:300px;
    min-height:100px;
    border:2px solid cyan;
    border-radius:12px;
    position:fixed;
    top:50px;
    left:260px;
    padding:4px 16px 10px;
}
.varViewer td,
.varViewer th {
    font-weight:normal;
    font-size:1.0875em;
    font-family:'Courier New',monospace;
    white-space:pre;
    color:#fff;
}
.varViewer th {
    text-align:center;
    padding-bottom:6px;
    border-bottom:2px solid #0cc;
}
.varViewer tr:nth-child(2) th {
    padding-bottom:3px;
    border-bottom:2px dotted #0cc;
}
.varViewer tr:nth-child(3) td {
    padding-top:6px;
}
.varViewer td[id$="C"] {
    text-align:right;
}
/* */
</style>
</head>
<body id="p">

<div id="outer">
    <h1>Rogue Eagles Radio Control Club; Medford, Oregon</h1>
    <ul class="nav">
        <li class="i"><a href="#"><img src="imgs/RE_Logo128e.png" alt="" width="128" height="128"></a></li>
        <li class="p urhere">IMAA Rally of Giants 2013 Poster</li>
        <li class="r"><a href="#">Registration</a></li>
        <li class="l"><a href="#">Location</a></li>
        <li class="f"><a href="#">Float Fly</a></li>
        <li class="s"><a href="#">Southern Oregon</a></li>
        <li class="a"><a href="#">Sponsors &amp; Vendors</a></li>
        <li class="c"><a href="#">Contact Us</a></li>
    </ul>
    <div class="canvas">
        <div class="frame">
            <img class="rogposter" src="imgs/RoGPoster2-.jpg" alt="" width="809" height="700">
        </div>
    </div>
</div>
<div id="footer">
    <p id="datebot">Updated:&nbsp; Sunday, December 02, 2012</p>
</div>
<table class="varViewer">
    <tr><th colspan="5">varViewer</th></tr>
    <tr><th>variable</th>  <td>     </td><th>value</th>     <td>    </td><th>remarks</th></tr>
    <tr><td id="r1cA"></td><td>  =  </td><td id="r1cC"></td><td>    </td><td>fixed value</td></tr>
    <tr><td id="r2cA"></td><td>  =  </td><td id="r2cC"></td><td>    </td><td>fixed value</td></tr>
    <tr><td id="r3cA"></td><td>  =  </td><td id="r3cC"></td><td>    </td><td>$nav.outerHeight()</td></tr>
    <tr><td id="r4cA"></td><td>  =  </td><td id="r4cC"></td><td>    </td><td>22 + navHeight + 25</td></tr>
    <tr><td id="r5cA"></td><td>  =  </td><td id="r5cC"></td><td>    </td><td>$canvas.offset().top</td></tr>
    <tr><td id="r6cA"></td><td>  =  </td><td id="r6cC"></td><td>    </td><td>$canvas.outerHeight()</td></tr>
    <tr><td id="r7cA"></td><td>  =  </td><td id="r7cC"></td><td>    </td><td>$page.scrollTop() - canvasTopOffset</td></tr>
    <tr><td id="r8cA"></td><td>  =  </td><td id="r8cC"></td><td>    </td><td>canvasHeight - canvasOutOfView</td></tr>
    <tr><td id="r9cA"></td><td>  =  </td><td id="r9cC"></td><td>    </td><td>canvasBottom - navBottom</td></tr>
</table>
<script type="text/javascript">
$(document).ready(function() {
    var $nav = $('.nav'),
        $page = $(document),
        $canvas = $('.canvas'),
        $outer = $('#outer'),
        navTopPosFixed = 22,
        navBottomPosAbs = 25,
        navHeight = $nav.outerHeight(),  // height = 574, outerHeight = 574
        navBottom = navTopPosFixed + navHeight + navBottomPosAbs,  // 621
        canvasTopOffset = $canvas.offset().top,  // 10 // distance from top of $(document)
        canvasHeight = $canvas.outerHeight();  // height = 708, outerHeight = 738
// write to varViewer
        $('#r1cA').html('navTopPosFixed');
        $('#r1cC').html(navTopPosFixed);
        $('#r2cA').html('navBottomPosAbs');
        $('#r2cC').html(navBottomPosAbs);
        $('#r3cA').html('navHeight');
        $('#r3cC').html(navHeight);
        $('#r4cA').html('navBottom');
        $('#r4cC').html(navBottom);
        $('#r5cA').html('canvasTopOffset');
        $('#r5cC').html(canvasTopOffset);
        $('#r6cA').html('canvasHeight');
        $('#r6cC').html(canvasHeight);
        $('#r7cA').html('canvasOutOfView');
        $('#r8cA').html('canvasBottom');
        $('#r9cA').html('- difference -');

    function calcNewPosition() {
        var canvasOutOfView = $page.scrollTop() - canvasTopOffset,
            canvasBottom = canvasHeight - canvasOutOfView;
        if (canvasBottom > navBottom) {
//            $nav.removeClass("absolute");
            $('.nav').css({'position':'fixed','top':'22px','bottom':'auto'});
        } else {
//            $nav.addClass("absolute");
            $('.nav').css({'position':'absolute','top':'auto','bottom':'25px'});
        }
// write to varViewer
        $('#r7cC').html(canvasOutOfView);
        $('#r8cC').html(canvasBottom);
        $('#r9cC').html(canvasBottom - navBottom);
    }
    $(window).scroll(function() {
        calcNewPosition();
    });
    $(window).trigger("scroll");   // Opera
});
</script>
</body>
</html>

:nanaman: :drink:

The 5th line of the jQuery script can be deleted. It was an experimental line that didn’t pan out. It serves no purpose.


        [color=red]$outer = $('#outer'),[/color]

Hi Ron,

Well done!
It’s great to see you finding your feet with jQuery.

Your changes seem fine to me, especially if it makes everything work as expected.

My comments:

For a small project such as this one this is fine and, as you say, it has the added bonus of not having to look for values in a different place when you’re working on it. Do bear in mind however, that this technique applies the styles in-line, so is convoluting your mark-up behind the scenes.

I think that looks better.

This is a great idea. Always be kind to your future self or anyone else who will work with the code.

We probably should have done this much earlier :slight_smile:

Go for it! There is not much jQuery magic going on here anyway. Mostly we are using jQuery to select elements and apply styles when the window is scrolled.

Yes!

Once you get the hang of how this thing works, it’s pathetically easy.

I didn’t like having to apply fixed values to the script. There ought to be a way to derive them. But it just didn’t seem possible to come up with that bottom number. What to do…

This evening, I had an “inspiration”… how about restructuring the menu a little… a possibility that has always been on the table, mind you. Instead of applying positioned values other than zero and auto, why not apply padding top and bottom to the menu box that equals those positioned offsets. By doing that, no offsets would have to be derived or remembered.

Well, IT WORKS! (of course :stuck_out_tongue: ). Less math, fewer lines of code and a perfect transitions in all browsers. Just add padding. No need to put those HTML inline styles in the script as a memory aid, either.

Flying high again! :weee:

Just for the record:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<!--
FileName: MenuX-2a.htm
http://www.sitepoint.com/forums/showthread.php?1110817-Fixed-Absolute-scrolling-vertical-menu
Thread: Fixed/Absolute scrolling vertical menu
Jun 11, 2013 05:08
ronpat
-->
<head>
    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
    <meta http-equiv="content-language" content="en-us">
    <meta http-equiv="content-style-type" content="text/css">
    <title>Menu eXperiments</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
    <style type="text/css">
html,
body {
    height:100%;
    padding:0px;
    margin:0px;
}
body {
    color:#000;
    font-size:100%;
    font-family:Verdana,sans-serif;
    background-color:#bdf;    /* set the background-color of the browser window here #bdf */
    overflow-y:scroll;
    padding:0;
    margin:0;
}
/* Opera Fix */
body:before {    /* thanks to Maleika (Kohoutec) */
    content:"";
    height:100%;
    float:left;
    width:0;
    margin-top:-32767px;    /* thank you Erik J - negate effect of float */
}
#outer {
    width:988px;
    min-height:100%;
    position:relative;
    margin:-50px auto 0;    /* footer height - this drags the outer 40px up through the top of the monitor */
}
.canvas {
/*    outline:1px solid magenta;  /* TEST OUTLINE */
    background-color:#532;    /* overall background-color */
    border-radius:20px;
    padding:15px 15px 15px 156px;
}
#footer {
    height:50px;
    clear:both;
}
#footer p {
    font-size:0.75em;
    font-family:'Trebuchet MS',sans-serif;
    text-align:center;
    padding-top:16px;
    margin:0;
}
/*  */
h1 {
    height:10px;
    border-top:50px solid #fff;    /* soak up negative margin and allows header to start at top of page */
    font-size:.6em;
    text-align:center;
    visibility:hidden;
    margin:0;
}
/*  */
/* PAGE BORDER & SIZE DIVs */
.content {
    background-color:#e9e8e4;
    background-image:url('../imgs/newsprint1.jpg');
    background-repeat:repeat;
    background-attachment:scroll;
    border-radius:12px;
    width:769px;          /* 817px wide */
    min-height:600px;
    padding:12px 24px 18px;
}
.frame {
    position:relative;    /* just in case you want to p:a something over the image */
}
#p .frame {
    position:static;      /* permits the menu tab to overlay the border around the poster image */
}
.frame img {
    display:block;
    border-radius:12px;
}

/* IMAGES */
.rogposter {
    border:4px solid #ddb600;    /* #ddb600 */
}

/* Navigation  ( screen: height >= 590px; width >= 988px ) */
.nav {
    list-style-type:none;
    position:fixed;
    left:50%;
    top:0;
    bottom:auto;
    padding:22px 0 25px;   /* the top and bottom offsets */
    margin:0 0 0 -484px;
}
.nav.absolute {
    position:absolute;
    top:auto;
    bottom:0;
}
.nav li {
    display:block;
    width:138px;
    text-align:center;
    font-weight:bold;
    font-size:18px;
    font-family:Verdana,sans-serif;
    padding:0;
    margin:0;
}
.nav li + li {
    margin-top:8px;
}
.nav li.urhere,
.nav li.dummy {
    padding:8px 0;
    width:134px;
}
.nav li.urhere {
    border-top:2px solid #ffd700;
    border-bottom:2px solid #ffd700;
    border-left:2px solid #ffd700;
    border-radius:10px 0 0 10px;
    background-color:#fff;
    color:#000;
    padding-right:10px;
}
.nav li.dummy {
    border:2px solid #865;
    border-radius:9px;
    background-color:#421;
    color:#865;
}
.nav li.p {
    margin-top:12px;
}
.nav li.a.urhere,
.nav li.c.urhere,
.nav li.f.urhere,
.nav li.l.urhere,
.nav li.r.urhere,
.nav li.s.urhere {
    background-color:#e9e8e4;
    background-image:url('../imgs/newsprint1.jpg');
    background-repeat:repeat;
    background-attachment:scroll;
}
.nav li.p.urhere {
    background-color:#88c4e6;
    position:relative;
}
.nav li.p.urhere:after {
    content:"";
    width:4px;
    position:absolute;
    top:0;
    right:-4px;
    bottom:0;
    background-color:#88c4e6;
}
.nav li.i a {
    display:table;
    border:0;
    border-radius:50%;
    padding:2px;
    margin:0 auto;
}
.nav li.i a:active {
    background-color:#f00;
}
.nav a {
    display:block;
    border:2px solid #865;
    border-radius:10px;
    background-color:#421;
    color:#f0f0f0;
    text-decoration:none;
    padding:8px 0;
}
.nav a:link,a:visited {}
.nav a:hover {
    color:#00f;
    border:2px solid #00f;
    background-color:#ccc;
}
.nav a:active {
    color:#f00;
    border:2px solid #f00;
    background-color:#eee;
}
.nav a img {
    display:block;
    border:none;
}

/* varViewer */
.varViewer {
    min-width:300px;
    min-height:100px;
    border:2px solid cyan;
    border-radius:12px;
    position:fixed;
    top:50px;
    left:260px;
    padding:4px 16px 10px;
}
.varViewer td,
.varViewer th {
    font-weight:normal;
    font-size:1.0875em;
    font-family:'Courier New',monospace;
    white-space:pre;
    color:#fff;
}
.varViewer th {
    text-align:center;
    padding-bottom:6px;
    border-bottom:2px solid #0cc;
}
.varViewer tr:nth-child(2) th {
    padding-bottom:3px;
    border-bottom:2px dotted #0cc;
}
.varViewer tr:nth-child(3) td {
    padding-top:6px;
}
.varViewer td[id$="C"] {
    text-align:right;
}
/* */
</style>
</head>
<body id="p">

<div id="outer">
    <h1>Rogue Eagles Radio Control Club; Medford, Oregon</h1>
    <ul class="nav">
        <li class="i"><a href="#"><img src="imgs/RE_Logo128e.png" alt="" width="128" height="128"></a></li>
        <li class="p"><a href="#">IMAA Rally of Giants 2013 Poster</a></li>
        <li class="r"><a href="#">Registration</a></li>
        <li class="l"><a href="#">Location</a></li>
        <li class="f"><a href="#">Float Fly</a></li>
        <li class="s"><a href="#">Southern Oregon</a></li>
        <li class="a"><a href="#">Sponsors &amp; Vendors</a></li>
        <li class="c urhere">Contact Us</li>
    </ul>
    <div class="canvas">
        <div class="frame">
            <img class="rogposter" src="imgs/RoGPoster2-.jpg" alt="" width="809" height="700">
        </div>
    </div>
</div>
<div id="footer">
    <p id="datebot">Updated:&nbsp; Sunday, December 02, 2012</p>
</div>
<table class="varViewer">
    <tr><th colspan="5">varViewer</th></tr>
    <tr><th>variable</th>  <td>     </td><th>value</th>     <td>    </td><th>remarks</th></tr>
    <tr><td id="r1cA"></td><td>  =  </td><td id="r1cC"></td><td>    </td><td></td></tr>
    <tr><td id="r2cA"></td><td>  =  </td><td id="r2cC"></td><td>    </td><td></td></tr>
    <tr><td id="r3cA"></td><td>  =  </td><td id="r3cC"></td><td>    </td><td></td></tr>
    <tr><td id="r4cA"></td><td>  =  </td><td id="r4cC"></td><td>    </td><td>$nav.outerHeight()</td></tr>
    <tr><td id="r5cA"></td><td>  =  </td><td id="r5cC"></td><td>    </td><td>$canvas.offset().top</td></tr>
    <tr><td id="r6cA"></td><td>  =  </td><td id="r6cC"></td><td>    </td><td>$canvas.outerHeight()</td></tr>
    <tr><td id="r7cA"></td><td>  =  </td><td id="r7cC"></td><td>    </td><td>$page.scrollTop() - canvasTopOffset</td></tr>
    <tr><td id="r8cA"></td><td>  =  </td><td id="r8cC"></td><td>    </td><td>canvasHeight - canvasOutOfView</td></tr>
    <tr><td id="r9cA"></td><td>  =  </td><td id="r9cC"></td><td>    </td><td>canvasBottom - navBottom</td></tr>
</table>
<script type="text/javascript">
$(document).ready(function() {
    var $nav = $('.nav'),
        $page = $(document),
        $canvas = $('.canvas'),
        navBottom = $nav.outerHeight(),  // height = 574, outerHeight = 621
        canvasTopOffset = $canvas.offset().top,  // 10 // distance from top of $(document)
        canvasHeight = $canvas.outerHeight();  // height = 708, outerHeight = 738
// write to varViewer
        $('#r4cA').html('navBottom');
        $('#r4cC').html(navBottom);
        $('#r5cA').html('canvasTopOffset');
        $('#r5cC').html(canvasTopOffset);
        $('#r6cA').html('canvasHeight');
        $('#r6cC').html(canvasHeight);
        $('#r7cA').html('canvasOutOfView');
        $('#r8cA').html('canvasBottom');
        $('#r9cA').html('- difference -');

    function calcNewPosition() {
        var canvasOutOfView = $page.scrollTop() - canvasTopOffset,
            canvasBottom = canvasHeight - canvasOutOfView;
        if (canvasBottom > navBottom) {
            $nav.removeClass("absolute");
        } else {
            $nav.addClass("absolute");
        }
// write to varViewer
        $('#r7cC').html(canvasOutOfView);
        $('#r8cC').html(canvasBottom);
        $('#r9cC').html(canvasBottom - navBottom);
    }
    $(window).scroll(function() {
        calcNewPosition();
    });
    $(window).trigger("scroll");   // Opera
});
</script>
</body>
</html>


Great stuff Ron.
However, I just tried your demo out on my PC and it broke horribly!!
See the attached screen shot.

… Nah, just kidding!
Of course it worked.
It was interesting to see how the code has altered from version one to the current version - both the CSS and the JS.
Thanks for taking the time to report back.