How do you stop a floating menu like this?

This baby is starting to take shape - where can I set the distance between the menu and top of browser once you start scrolling? th emenu shouldn’t start moving right away it should wait until it’s like 5px from the top of the browser before it starts moving, also the menu is still jittery in IE, any idea why? in ff and chrome it is smooth as a baby’s bottom.

The element assigned to the elementAboveContainer variable is the point at which it should stop scrolling. Let’s get rid of that whole situation by removing the elementAboveContainer variable, and removing the offsetTop variable.

Remove the elementAboveContainer from the in-page script:


var updateSection = function () {
    var nav = $('.menu'),
        container = $('.content')[s][COLOR="Red"],
        elementAboveContainer = $('.header')[/COLOR][/s];
    fixedSection(nav, container[s][COLOR="red"], elementAboveContainer[/COLOR][/s]);
};

In the script, remove the elementAboveContainer and offsetTop parts:


function fixedSection(nav, container[s][COLOR="red"], elementAboveContainer[/COLOR][/s]) {
    var [s][COLOR="red"]offsetTop = $(elementAboveContainer).height(),[/COLOR][/s]
        scrollTop = $(window).scrollTop()[s][COLOR="red"] + offsetTop[/COLOR][/s],
    ...
    top = [s][COLOR="red"]offsetTop + [/COLOR][/s]Number($(container).css('padding-top').replace('px', ''));

Now the menu section stops moving when it gets to the top of the screen.

That’s something that you just need to put up with in IE, because IE below version 7 completely fails to understand the “fixed” CSS setting. It’s unavoidable. There’s also a CSS issue that affects IE 7, and as a result, a different technique is used for IE 7 and below.

You might get smoother results by increasing the frequency of the update from 50 milliseconds down to somewhere like 20, but it’s not likely to be very noticable.

the menu in the link doesn’t stutter in IE like this one, I thought you used the same code basically?

I’m using IE 7, if I change this if ($.browser.msie && $.browser.version < “8”) { to if ($.browser.msie && $.browser.version < “7”) {

the menu is smooth in IE7, is there a way I can specify multiple versions of IE?

If I remove all of the code you slashed out then the menu stops working.

Then something is obviously going wrong with what you changed. Put up a test page, link to it, and we’ll find out the fault and fix it.

Here’s what I’m trying to work on now - I need to be able to change the starting position of the menu inside the container… like move it left/right up/down - then I need to be able to adjust the distance between the menu and the top of the browser once I start scrolling… the menu should start moving until it’s about 5px from the top of the browser… and then it should stay 5px from the top as you scroll - is this possible?

Yes it is, you have the code changes to achieve all of that in [post #22](post http://www.sitepoint.com/forums/showpost.php?p=4787784&postcount=22)

here be the code that dont be working i removed the parts you said to remove

function fixedSection(nav, container) {
var scrollTop = $(window).scrollTop() + offsetTop,
topOfContainer = $(container).offset().top,
position = ‘’,
top = 0;
if (scrollTop >= topOfContainer && topOfContainer + $(container).height() >= scrollTop +

$(nav).height()) {
if ($.browser.msie && $.browser.version < “8”) {
position = ‘relative’;
top = scrollTop - topOfContainer;
} else {
position = ‘fixed’;
top = Number($(container).css(‘padding-top’).replace(‘px’, ‘’));
}
} else {
position = ‘relative’;
top = topOfContainer + $(container).height() <= scrollTop + $(nav).height() ?

$(container).height() - $(nav).height() : 0;
}
$(nav).css({position: position, top: top + ‘px’});
}

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN” “http://www.w3.org/TR/html4/strict.dtd”>
<html>
<head>
<meta http-equiv=“Content-Type” content=“text/html; charset=utf-8”>
<title>floating menu test</title>
<link type=“text/css” rel=“stylesheet” href=“style.css”>
<script type=“text/javascript” src=“https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js”></script>
<script type=“text/javascript” src=“fixedSection.js”></script>
<script type=“text/javascript”>
$(function () {
var updateSection = function () {
var nav = $(‘.menu’),
container = $(‘.content’);
fixedSection(nav, container, elementAboveContainer);
};
window.setInterval(updateSection, 50);
});
</script>
</head>
<body>
<div class=“header”>Header</div>
<div class=“content”>
<div class=“menu”>menu</div>
<div class=“text”>Some text</div>
</div>
<div class=“footer”>Footer</div>
</body>
</html>

I can still see a reference to elementAboveContainer in your code there.

I could see a couple of things wrong

fixedSection.js

function fixedSection(nav, container) {
    var scrollTop = $(window).scrollTop() + $(window).offsetTop,
    topOfContainer = container.offset().top, position = '', top = 0;
    
    if (scrollTop >= topOfContainer && topOfContainer + container.height() >= scrollTop + $(nav).height()) {
        if ($.browser.msie && $.browser.version < "8") {
            position = 'relative';
            top = scrollTop - topOfContainer;
        } else {
            position = 'fixed';
            top = Number(container.css('padding-top').replace('px', ''));
        }
    } else {
        position = 'relative';
        top = (topOfContainer + container.height() <= scrollTop + $(nav).height()) ? 
            container.height() - $(nav).height() : 0;
    }
    
    $(nav).css({position: position, top: top + 'px'});
}
  • $(window).scrollTop() + offsetTop is not a valid method, offsetTop needs either $(document) or $(window) attached to it

General JavaScript

$(document).ready(function() {
    var updateSection = function() {
        var nav = $('.menu'), container = $('.content');
        fixedSection(nav, container);
    };
    
    window.setInterval(updateSection, 50);
});
  • Calling out $(‘.menu’) and $(‘.content’) within the <head> tags cannot be done as the DOM has not loaded yet, using $(document).ready() fixes this

You’ll be please to note that jQuery provides an updated technique for document ready

These two sections of code perform the same identical task:


$(document).ready(function () {

});


$(function () {

});

The jQuery(callback) page has details about it.

I removed the abovecontainer in the code below and it still doesn’t work

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN” “http://www.w3.org/TR/html4/strict.dtd”>
<html>
<head>
<meta http-equiv=“Content-Type” content=“text/html; charset=utf-8”>
<title>floating menu test</title>
<link type=“text/css” rel=“stylesheet” href=“style.css”>
<script type=“text/javascript” src=“https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js”></script>
<script type=“text/javascript” src=“fixedSection.js”></script>
<script type=“text/javascript”>
$(function () {
var updateSection = function () {
var nav = $(‘.menu’),
container = $(‘.content’);
fixedSection(nav, container);
};
window.setInterval(updateSection, 50);
});
</script>
</head>
<body>
<div class=“header”>Header</div>
<div class=“content”>
<div class=“menu”>menu</div>
<div class=“text”>Some text</div>
</div>
<div class=“footer”>Footer</div>
</body>
</html>

Have you tested this because it doesn’t work

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN” “http://www.w3.org/TR/html4/strict.dtd”>
<html>
<head>
<meta http-equiv=“Content-Type” content=“text/html; charset=utf-8”>
<title>floating menu test</title>
<link type=“text/css” rel=“stylesheet” href=“style.css”>
<script type=“text/javascript” src=“https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js”></script>
<script type=“text/javascript” src=“fixedSection.js”></script>
<script type=“text/javascript”>
$(function () {
var updateSection = function () {
var nav = $(‘.menu’),
container = $(‘.content’);
fixedSection(nav, container);
};
window.setInterval(updateSection, 50);
});
</script>
</head>
<body>
<div class=“header”>Header</div>
<div class=“content”>
<div class=“menu”>menu</div>
<div class=“text”>Some text</div>
</div>
<div class=“footer”>Footer</div>
</body>
</html>

function fixedSection(nav, container) {
var scrollTop = $(window).scrollTop() + offsetTop,
topOfContainer = $(container).offset().top,
position = ‘’,
top = 0;
if (scrollTop >= topOfContainer && topOfContainer + $(container).height() >= scrollTop + $(nav).height()) {
if ($.browser.msie && $.browser.version < “8”) {
position = ‘relative’;
top = scrollTop - topOfContainer;
} else {
position = ‘fixed’;
top = Number($(container).css(‘padding-top’).replace(‘px’, ‘’));
}
} else {
position = ‘relative’;
top = topOfContainer + $(container).height() <= scrollTop + $(nav).height() ? $(container).height() - $(nav).height() : 0;
}
$(nav).css({position: position, top: top + ‘px’});
}

Yes, the advised changes have been tested.

There is for example a " + offsetTop" section that still needs to be removed.

Thanks for the note [COLOR=#336633][B]pmw57[/B][/COLOR], guess i should do more reading then coding.

@Gitman: No i didn’t test it because all i saw was that main error i found, do you have any CSS styles for this as using plain text really isn’t good for testing.

The code (CSS, HTML, JavaScript) is all in post #18 with the requested tweak adjustments in [url=“http://www.sitepoint.com/forums/showpost.php?p=4787784&postcount=22”]post #22

You edited your old post and added that! lol, so I removed it and it’s looking good… but what about the IE issue? I need a fix for that… if I change the IE number to something less than 8 in that code, it is smooth in ie7, however the starting position is centered in the middle of the page and not to the left.

is there anyway to fix this, because I think I almost have what I need now!

That was actually performed somewhat earlier. The most recent edit of that post was to change “he” to “the”. :rolleyes:

Someone who knows more about CSS than I would have to wade in to offer a solution, if available.

This works pretty good… but I need to be able to specify the starting position of the menu in the container… right now it starts out at the top of the container, and I would like it to start, for instance, 300px from the top of the container… and also, I don’t want the menu to start moving until the distance between the top of the menu and the top of the browser is a certain height, say 5px. I would also need to adjust left/right placement inside the container.

Oh yea, and in IE7 and below, it’s jerky when you scroll - I need that fixed somehow… does anyone know if all of these things are possible by modifying this code or if I will need to do this a different way?

Thanks!

style.css


body {
    margin: 0;
    padding: 0;
}
.header {
    height: 100px;
    background-color: darkred;
    text-align: center;
    color: #fff;
    font-size: 3em;
}
.content {
    padding: 10px;
    width: 900px;
    margin: 0 auto;
    background-color: #f1f1f1;
    position: relative;
}
    .content .text {
        height: 1000px;
        background-color: #ddd;
        margin-left: 250px;
        text-align: center;
        color: #333;
        font-size: 2em;
    }
    .content .menu {
        position: absolute;
        float: left;
        width: 240px;
        height: 450px;
        background: green;
        text-align: center;
        color: #fff;
        font-size: 2em;
    }
.footer {
    height: 500px;
    background-color: blue;
    text-align: center;
    color: #fff;
    font-size: 3em;
}

demo.html


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>floating menu test</title>
    <link type="text/css" rel="stylesheet" href="style.css">
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
    <script type="text/javascript" src="fixedSection.js"></script>
    <script type="text/javascript">
    $(function () {
        var updateSection = function () {
            var nav = $('.menu'),
                container = $('.content'),
                elementAboveContainer = $('.header');
            fixedSection(nav, container, elementAboveContainer);
        };
        window.setInterval(updateSection, 50);
    });
    </script>
</head>
<body>
    <div class="header">Header</div>
    <div class="content">
        <div class="menu">menu</div>
        <div class="text">Some text</div>
    </div>
    <div class="footer">Footer</div>
</body>
</html>

fixedSection.js


function fixedSection(nav, container, elementAboveContainer) {
    var offsetTop = $(elementAboveContainer).height(),
        scrollTop = $(window).scrollTop() + offsetTop,
        topOfContainer = $(container).offset().top,
        position = '',
        top = 0;
    if (scrollTop >= topOfContainer && topOfContainer + $(container).height() >= scrollTop + $(nav).height()) {
        if ($.browser.msie && $.browser.version < "8") {
            position = 'relative';
            top = scrollTop - topOfContainer;
        } else {
            position = 'fixed';
            top = offsetTop + Number($(container).css('padding-top').replace('px', ''));
        }
    } else {
        position = 'relative';
        top = topOfContainer + $(container).height() <= scrollTop + $(nav).height() ? $(container).height() - $(nav).height() : 0;
    }
    $(nav).css({position: position, top: top + 'px'});
}