Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bootstrap affix dynamically on resize

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?
like image 292
user3332109 Avatar asked Feb 27 '14 21:02

user3332109


2 Answers

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

$('#navigation').affix({
  offset: {
    top: function() { return $('#hero').height(); }
  }
});
like image 176
domachine Avatar answered Oct 20 '22 02:10

domachine


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');
            }
        });
    });
like image 31
Hrvoje Golcic Avatar answered Oct 20 '22 01:10

Hrvoje Golcic