My landing page requires a unique feature: when a user enters a specific <section>
, that section should become fixed while the elements inside the corresponding <div>
start scrolling. Once the inner div
has finished scrolling, the parent <section>
should resume normal scrolling behavior and smoothly move to the top with a scroll.
I attempted to recreate this structure on jsFiddle but didn't achieve the desired functionality.
Check out my attempt on jsFiddle here.
I aim to replicate the behavior seen on this website. Specifically, Section SS as shown in the following image: https://i.sstatic.net/is4WR.png
Here's the HTML structure:
... Previous sections
<section ref="stickyDiv" class="scroller py-sm-128">
<div class="">
<div ref="wrapper" @scroll="scrollerListener" class="wrapper-box">
<div class="d-flex px-sm-128">
<h3 class="section-heading">Access to all the exclusive opportunities</h3>
<div class="col-sm-6">
<img class="img-fluid"
src="https://res.cloudinary.com/stack-finance/image/upload/v1663728853/app-assets/v2/mask_group_590_e5gbgr.png"
>
</div>
</div>
<div class="d-flex px-sm-128">
<h3 class="section-heading">Access to all the exclusive opportunities</h3>
<div class="col-sm-6">
<img class="img-fluid"
src="https://res.cloudinary.com/stack-finance/image/upload/v1663728853/app-assets/v2/mask_group_590_e5gbgr.png"
>
</div>
</div>
<div class="d-flex px-sm-128">
<h3 class="section-heading">Access to all the exclusive opportunities</h3>
<div class="col-sm-6">
<img class="img-fluid"
src="https://res.cloudinary.com/stack-finance/image/upload/v1663728853/app-assets/v2/mask_group_590_e5gbgr.png"
>
</div>
</div>
</div>
</div>
</section>
... Further sections
Vue.js Method:
methods: {
...
listenBodyScroll(e) {
if (this.isMobile) {
return;
}
const stickyDiv = this.$refs.stickyDiv;
const wrapper = this.$refs.wrapper;
const dim = stickyDiv.getBoundingClientRect();
console.log(dim.y, dim.height, '---scrollTop');
if (dim.y <= 0) {
if (Math.ceil(dim.height) <= Math.abs(dim.y)) {
stickyDiv.style.position = 'relative';
stickyDiv.style.top = 'auto';
stickyDiv.style.height = 'auto';
wrapper.style.overflowY = 'hidden';
wrapper.scrollTop = wrapper.scrollHeight;
return;
}
wrapper.focus();
stickyDiv.style.position = 'sticky';
stickyDiv.style.top = '100px';
stickyDiv.style.height = '100vh';
wrapper.style.overflowY = 'auto';
}
},
scrollerListener({ target: { scrollTop, offsetHeight, scrollHeight, style } }) {
if (this.isMobile) {
return;
}
const stickyDiv = this.$refs.stickyDiv;
if ((Math.ceil(scrollTop) + offsetHeight) >= scrollHeight) {
stickyDiv.style.position = 'relative';
stickyDiv.style.top = 'auto';
stickyDiv.style.height = 'auto';
style.overflowY = 'hidden';
console.log('bottom!');
}
}
}
VUE Directive for v-scroll:
Vue.directive('scroll', {
inserted(el, binding) {
const f = function(evt) {
if (binding.value(evt, el)) {
window.removeEventListener('scroll', f);
}
};
window.addEventListener('scroll', f);
}
});