@ chris-spittles提供的解决方案为我提供了很多帮助,但我还想提供一个普通的Javascript解决方案。此外,我添加了一些功能,用于在您不希望其内容区域继续被固定的情况下处理最后的粘性问题。
https://codepen.io/jamigibbs/pen/QZWjBy
const StickySubsections = (function(){
let el
return {
elements: function () {
return {
stickies: [...document.querySelectorAll('.followMeBar')]
}
},
init: function () {
el = this.elements()
this.load()
},
load: function () {
this.setupStickyWrap()
window.addEventListener('scroll', () => this.whenScrolling())
},
setupStickyWrap: function(){
el.stickies.forEach((sticky, i) => {
const stickyWrap = this.addWrap(sticky, 'sticky-wrap')
const heightToTop = sticky.getBoundingClientRect().top + window.scrollY
const outerHeight = sticky.offsetHeight
stickyWrap.parentElement.id = `sticky-content-${i}`
sticky.setAttribute('data-originalPosition', heightToTop)
sticky.setAttribute('data-originalHeight', outerHeight)
stickyWrap.style.height = outerHeight + 'px'
})
},
addWrap: function(el, className, wrap = 'div') {
const wrapper = document.createElement(wrap)
wrapper.classList.add(className)
el.parentNode.insertBefore(wrapper, el)
wrapper.appendChild(el)
return wrapper
},
elementExists: function(el){
return typeof(el) != 'undefined' && el != null
},
stickyPosition: function(el){
return el.getAttribute('data-originalPosition')
},
nextStickyPosition: function(current, next){
return next.getAttribute('data-originalPosition') - current.getAttribute('data-originalHeight')
},
scrollingPositionTop: function(el){
return el.getBoundingClientRect().top + window.scrollY
},
offsetTop: function(el){
return el.getBoundingClientRect().top
},
scrollingPositionBottom: function(el){
return el.getBoundingClientRect().bottom + window.scrollY
},
headerPosition: function(){
return window.scrollY
},
bottomSectionHit: function(contentElement, sticky){
const contentSection = document.getElementById(contentElement)
const sectionBottom = contentSection.getBoundingClientRect().bottom + window.scrollY
const stickyPositionScrolling = sticky.getBoundingClientRect().bottom + window.scrollY
return stickyPositionScrolling >= sectionBottom
},
whenScrolling: function() {
el.stickies.forEach((sticky, i) => {
const nextSticky = el.stickies[i + 1]
const prevSticky = el.stickies[i - 1]
if (this.stickyPosition(sticky) <= this.headerPosition()) {
sticky.classList.add('fixed')
if (this.elementExists(nextSticky)) {
while (this.scrollingPositionBottom(sticky) >= this.nextStickyPosition(sticky, nextSticky) + 50) {
sticky.classList.add('absolute')
sticky.style.top = this.nextStickyPosition(sticky, nextSticky)
}
} else {
if (this.bottomSectionHit(`sticky-content-${i}`, sticky)) {
sticky.classList.remove('fixed')
}
}
} else {
sticky.classList.remove('fixed')
if (this.elementExists(prevSticky) && window.scrollY <= this.stickyPosition(sticky)){
prevSticky.classList.remove('absolute')
prevSticky.removeAttribute('style')
}
}
})
}
}
}())
StickySubsections.init()