using affix in Bootstrap 4

In bootstrap 4 Dropped the Affix jQuery plugin.

So we need to manually ad the plugin component or use custom script to work affix feature in bootstrap 4. there are so many methods we can use for this.

but i recommend following script for the scenario. this is acctualy found from the bootstrap 3 version in github.

(function ($) {
'use strict';

// AFFIX CLASS DEFINITION
// ======================

var Affix = function (element, options) {
this.options = $.extend({}, Affix.DEFAULTS, options)

var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)

this.$target = target
.on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
.on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))

this.$element     = $(element)
this.affixed      = null
this.unpin        = null
this.pinnedOffset = null

this.checkPosition()
}

Affix.VERSION  = '3.4.0'

Affix.RESET    = 'affix affix-top affix-bottom'

Affix.DEFAULTS = {
offset: 0,
target: window
}

Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
var scrollTop    = this.$target.scrollTop()
var position     = this.$element.offset()
var targetHeight = this.$target.height()

if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false

if (this.affixed == 'bottom') {
if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
}

var initializing   = this.affixed == null
var colliderTop    = initializing ? scrollTop : position.top
var colliderHeight = initializing ? targetHeight : height

if (offsetTop != null && scrollTop <= offsetTop) return 'top' if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'

return false
}

Affix.prototype.getPinnedOffset = function () {
if (this.pinnedOffset) return this.pinnedOffset
this.$element.removeClass(Affix.RESET).addClass('affix')
var scrollTop = this.$target.scrollTop()
var position  = this.$element.offset()
return (this.pinnedOffset = position.top - scrollTop)
}

Affix.prototype.checkPositionWithEventLoop = function () {
setTimeout($.proxy(this.checkPosition, this), 1)
}

Affix.prototype.checkPosition = function () {
if (!this.$element.is(':visible')) return

var height       = this.$element.height()
var offset       = this.options.offset
var offsetTop    = offset.top
var offsetBottom = offset.bottom
var scrollHeight = Math.max($(document).height(), $(document.body).height())

if (typeof offset != 'object')         offsetBottom = offsetTop = offset
if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)

var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)

if (this.affixed != affix) {
if (this.unpin != null) this.$element.css('top', '')

var affixType = 'affix' + (affix ? '-' + affix : '')
var e         = $.Event(affixType + '.bs.affix')

this.$element.trigger(e)

if (e.isDefaultPrevented()) return

this.affixed = affix
this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null

this.$element
.removeClass(Affix.RESET)
.addClass(affixType)
.trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
}

if (affix == 'bottom') {
this.$element.offset({
top: scrollHeight - height - offsetBottom
})
}
}

// AFFIX PLUGIN DEFINITION
// =======================

function Plugin(option) {
return this.each(function () {
var $this   = $(this)
var data    = $this.data('bs.affix')
var options = typeof option == 'object' && option

if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
if (typeof option == 'string') data[option]()
})
}

var old = $.fn.affix

$.fn.affix             = Plugin
$.fn.affix.Constructor = Affix

// AFFIX NO CONFLICT
// =================

$.fn.affix.noConflict = function () {
$.fn.affix = old
return this
}

// AFFIX DATA-API
// ==============

$(window).on('load', function () {
$('[data-spy="affix"]').each(function () {
var $spy = $(this)
var data = $spy.data()

data.offset = data.offset || {}

if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
if (data.offsetTop    != null) data.offset.top    = data.offsetTop

Plugin.call($spy, data)
})
})

})(jQuery);

How it works

The affix plugin toggles between three classes: .affix.affix-top, and .affix-bottom. Each class represents a particular state. You must add CSS properties to handle the actual positions, with the exception of position:fixed on the .affix class.

    • The plugin adds the .affix-top or .affix-bottom class to indicate the element is in its top-most or bottom-most position. Positioning with CSS is not required at this point.

 

    • Scrolling past the affixed element triggers the actual affixing – This is where the plugin replaces the .affix-topor .affix-bottom class with the .affix class (sets position:fixed). At this point, you must add the CSS top or bottom property to position the affixed element in the page.

 

  • If a bottom offset is defined, scrolling past it replaces the .affix class with .affix-bottom. Since offsets are optional, setting one requires you to set the appropriate CSS. In this case, add position:absolute when necessary.
0 0 vote
Article Rating

by kushan


Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Gayan Alahakoon
Gayan Alahakoon
1 year ago

this article is helpful.Thank You 🙂