6

I have a 100% height div with a nav underneath it and more content under that.

When the user scrolls passed the nav it sticks to the top of the page and when the user goes back to the 100% height div the nav is left behind.

As the div is 100% height the 'data-offset-top' for the nav needs to change dynamically.

The following code works for that:

    $('#navigation').affix({
        offset: {
            top: $('#hero').height()
        }
    });

However when I resize the page the value of the offset does not get readded to the offset.

The following code checks for the page height to change and then gives the new height to the data-offset-top but it does not ` function affixChange() {

     $('#navigation').attr('data-offset-top', $('#hero').height());
    $('#navigation').affix({
        offset: {
            top: $('#hero').height()
        }
    }); 
 }

affixChange();
setInterval(function(){
 affixChange();
console.log($('#hero').height());
}, 1000)
  1. Why is my method not working?
  2. Is there a better way to do this?
madth3
  • 7,275
  • 12
  • 50
  • 74
user3332109
  • 71
  • 1
  • 3

3 Answers3

19

Bootstrap gives you the possibility to pass a function to calculate the offset dynamically:

$('#navigation').affix({
  offset: {
    top: function() { return $('#hero').height(); }
  }
});
domachine
  • 1,119
  • 1
  • 12
  • 20
  • In my case I was having the navigation affix after a carousel of images, this required me to subtract one from the height returned - `$('.image-slider').height() - 1` otherwise it would toggle the affix property on and off when it navigated to the first hashed location. – a_dreb Sep 21 '15 at 02:13
  • @domachine - dude you're a Legend! –  Aug 29 '16 at 16:09
1

Unfortunately if you need data-offset-top to be set dynamically you need to handle this manually. While domachine provides the correct answer I wanted to offer here a way to re-calculate the value on page resize and also to add a space holder so that affixing runs smooth e.g. no page jumping when the contents gets affixed. This was an issue for me.

  • It re-calculates data-offset-top dynamically
  • It sets the offset space dynamically. The space will replace affix when affixed

So I use the following HTML:

<div class="my-affix" data-spy="affix" data-offset-top-dynamic="true" data-content-space-holder="#my-affix-space-holder"></div>
<div id="my-affix-space-holder"></div>

The following CSS:

.my-affix + #my-affix-space-holder {
    display: none;
}
.my-affix.affix + #my-affix-space-holder {
    display: block;
}

And a JS script:

var $dynamicAffixes = $('[data-offset-top-dynamic]');
    $dynamicAffixes.each(function(){
        // data-target is used for the element that should be affixed while data-spy is used to have some scroll breakpoint
        var $thisAffix = $(this);
        var $thisAffixMarginPlaceholder = $($thisAffix.attr('data-content-space-holder'));
        var currentAffixHeight = $thisAffix.outerHeight();

        // Assign the affix height to content placeholder - to add a margin in the page because of missing content
        $thisAffixMarginPlaceholder.css('height', currentAffixHeight);

        // Initialize affix height where it should trigger to become sticky
        $thisAffix.affix({
            offset: {
                top: Math.round($(this).offset().top)
            }
        });

        $(window).on('resize', function(){
            var isAlreadyAffixed = false;

            // Restore affix to its original position if scrolled already so we can calculate properly
            if ($thisAffix.hasClass('affix')) {
                $thisAffix.removeClass('affix');
                isAlreadyAffixed = true;
            }

            var currentAffixPosition = Math.round($thisAffix.offset().top);
            var currentAffixHeight = $thisAffix.outerHeight();
            $thisAffix.data('bs.affix').options.offset.top = currentAffixPosition; // a hack
            $thisAffixMarginPlaceholder.css('height', currentAffixHeight);

            if (isAlreadyAffixed) {
                $thisAffix.addClass('affix');
                $thisAffix.affix('checkPosition');
            }
        });
    });
Hrvoje Golcic
  • 3,446
  • 1
  • 29
  • 33
  • 1
    That's really good, I couldn't stand the jump the regular bootstrap affix caused. It's a lot more code, but worth it in my view. Nice & smooth. Not sure why you haven't received an up-vote for this, but here's your first! – ShrapNull Jul 08 '18 at 20:39
0

Have you tried monitoring the window for a resize event?

    $(window).resize(function() {
  affixChange();
});
user1133128
  • 164
  • 3