I solved it here:
https://codesandbox.io/s/vue-2-playground-forked-pkh2hr?file=/src/components/SidebarAndContent.vue
SidebarAndContent.vue:
<template>
<div>
<div id="sidebar" :class="sideBarFixed ? 'fixed' : ''" :style="[{ top: `${sideBarTop}px` }]">
<h1>Sidebar</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eget tellus non tortor laoreet euismod. Nunc mattis
fermentum aliquet. Donec elementum sagittis suscipit. Morbi vitae quam est. Vestibulum ante ipsum primis in
faucibus orci luctus et ultrices posuere cubilia Curae; Proin at tellus vitae nisl aliquet eleifend eget
vehicula tortor. In tristique volutpat ante, at rhoncus felis scelerisque eu. Sed eros dolor, ultrices vitae
tincidunt ac, dignissim in tellus. Nulla blandit cursus eros, non tincidunt velit sollicitudin mollis. Phasellus
tellus velit, faucibus vel faucibus ut, luctus at mauris. Nunc in lacinia nibh.</p>
<p>Proin a ipsum quis leo mattis molestie. Pellentesque nunc dui, dictum ut semper et, vestibulum ut diam.
Suspendisse volutpat suscipit mi, quis lacinia elit egestas a. Vestibulum id rhoncus massa. Nunc sed elit eu
mauris vulputate ultricies. Proin pulvinar ipsum ut nisl ullamcorper dictum. Donec sit amet dolor ipsum.
Pellentesque facilisis, metus dignissim porttitor mollis, nunc metus convallis felis, vel dictum urna justo sit
amet diam. Aenean pellentesque scelerisque nunc quis condimentum. Cras sed mauris at magna cursus tristique.</p>
</div>
<div id="content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eget tellus non tortor laoreet euismod. Nunc mattis
fermentum aliquet. Donec elementum sagittis suscipit. Morbi vitae quam est. Vestibulum ante ipsum primis in
faucibus orci luctus et ultrices posuere cubilia Curae; Proin at tellus vitae nisl aliquet eleifend eget
vehicula tortor. In tristique volutpat ante, at rhoncus felis scelerisque eu. Sed eros dolor, ultrices vitae
tincidunt ac, dignissim in tellus. Nulla blandit cursus eros, non tincidunt velit sollicitudin mollis. Phasellus
tellus velit, faucibus vel faucibus ut, luctus at mauris. Nunc in lacinia nibh.</p>
<p>Proin a ipsum quis leo mattis molestie. Pellentesque nunc dui, dictum ut semper et, vestibulum ut diam.
Suspendisse volutpat suscipit mi, quis lacinia elit egestas a. Vestibulum id rhoncus massa. Nunc sed elit eu
mauris vulputate ultricies. Proin pulvinar ipsum ut nisl ullamcorper dictum. Donec sit amet dolor ipsum.
Pellentesque facilisis, metus dignissim porttitor mollis, nunc metus convallis felis, vel dictum urna justo sit
amet diam. Aenean pellentesque scelerisque nunc quis condimentum. Cras sed mauris at magna cursus tristique.</p>
<p>Nunc arcu mi, placerat vitae condimentum dapibus, volutpat quis libero. Class aptent taciti sociosqu ad litora
torquent per conubia nostra, per inceptos himenaeos. Suspendisse potenti. Nulla varius erat vel dolor dictum
vestibulum. Quisque adipiscing tincidunt nulla, sed sagittis risus imperdiet sit amet. Donec ultrices tristique
adipiscing. Ut iaculis volutpat mauris. Proin bibendum, diam vel venenatis posuere, felis orci venenatis tortor,
vel egestas nisl tellus accumsan elit. Nullam feugiat odio purus, sed bibendum est. Donec gravida magna sit amet
libero tincidunt ullamcorper.</p>
<p>Nulla facilisi. Ut porttitor semper condimentum. Integer luctus varius nisi, ac condimentum sapien auctor
volutpat. Cras molestie consectetur libero. Phasellus risus urna, imperdiet non porttitor eget, adipiscing
adipiscing magna. Nam semper, felis a condimentum viverra, massa ante varius odio, quis pretium enim neque quis
libero. Nulla massa dolor, imperdiet sed molestie semper, adipiscing at est. Etiam eget quam sed orci vestibulum
ullamcorper. Donec mi sapien, adipiscing in eleifend a, tempor vel velit.</p>
<p>Proin nec suscipit nibh. Nulla varius purus et dolor pellentesque ullamcorper. Vestibulum blandit quam et
sapien lobortis blandit. Nulla eu eros lacus, et mattis magna. In lobortis luctus varius. Maecenas in purus
odio, quis porttitor felis. Sed id nisi massa, sit amet placerat magna. Curabitur imperdiet hendrerit imperdiet.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus lobortis nunc sit
amet eros vulputate ac eleifend elit convallis. Quisque commodo erat quis enim tincidunt ac lacinia urna
pretium. Curabitur luctus leo nec turpis sagittis ut porta dui blandit.</p>
<p>Nunc arcu mi, placerat vitae condimentum dapibus, volutpat quis libero. Class aptent taciti sociosqu ad litora
torquent per conubia nostra, per inceptos himenaeos. Suspendisse potenti. Nulla varius erat vel dolor dictum
vestibulum. Quisque adipiscing tincidunt nulla, sed sagittis risus imperdiet sit amet. Donec ultrices tristique
adipiscing. Ut iaculis volutpat mauris. Proin bibendum, diam vel venenatis posuere, felis orci venenatis tortor,
vel egestas nisl tellus accumsan elit. Nullam feugiat odio purus, sed bibendum est. Donec gravida magna sit amet
libero tincidunt ullamcorper.</p>
<p>Nulla facilisi. Ut porttitor semper condimentum. Integer luctus varius nisi, ac condimentum sapien auctor
volutpat. Cras molestie consectetur libero. Phasellus risus urna, imperdiet non porttitor eget, adipiscing
adipiscing magna. Nam semper, felis a condimentum viverra, massa ante varius odio, quis pretium enim neque quis
libero. Nulla massa dolor, imperdiet sed molestie semper, adipiscing at est. Etiam eget quam sed orci vestibulum
ullamcorper. Donec mi sapien, adipiscing in eleifend a, tempor vel velit.</p>
<p>Proin nec suscipit nibh. Nulla varius purus et dolor pellentesque ullamcorper. Vestibulum blandit quam et
sapien lobortis blandit. Nulla eu eros lacus, et mattis magna. In lobortis luctus varius. Maecenas in purus
odio, quis porttitor felis. Sed id nisi massa, sit amet placerat magna. Curabitur imperdiet hendrerit imperdiet.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus lobortis nunc sit
amet eros vulputate ac eleifend elit convallis. Quisque commodo erat quis enim tincidunt ac lacinia urna
pretium. Curabitur luctus leo nec turpis sagittis ut porta dui blandit.</p>
<p>Nunc arcu mi, placerat vitae condimentum dapibus, volutpat quis libero. Class aptent taciti sociosqu ad litora
torquent per conubia nostra, per inceptos himenaeos. Suspendisse potenti. Nulla varius erat vel dolor dictum
vestibulum. Quisque adipiscing tincidunt nulla, sed sagittis risus imperdiet sit amet. Donec ultrices tristique
adipiscing. Ut iaculis volutpat mauris. Proin bibendum, diam vel venenatis posuere, felis orci venenatis tortor,
vel egestas nisl tellus accumsan elit. Nullam feugiat odio purus, sed bibendum est. Donec gravida magna sit amet
libero tincidunt ullamcorper.</p>
<p>Nulla facilisi. Ut porttitor semper condimentum. Integer luctus varius nisi, ac condimentum sapien auctor
volutpat. Cras molestie consectetur libero. Phasellus risus urna, imperdiet non porttitor eget, adipiscing
adipiscing magna. Nam semper, felis a condimentum viverra, massa ante varius odio, quis pretium enim neque quis
libero. Nulla massa dolor, imperdiet sed molestie semper, adipiscing at est. Etiam eget quam sed orci vestibulum
ullamcorper. Donec mi sapien, adipiscing in eleifend a, tempor vel velit.</p>
<p>Proin nec suscipit nibh. Nulla varius purus et dolor pellentesque ullamcorper. Vestibulum blandit quam et
sapien lobortis blandit. Nulla eu eros lacus, et mattis magna. In lobortis luctus varius. Maecenas in purus
odio, quis porttitor felis. Sed id nisi massa, sit amet placerat magna. Curabitur imperdiet hendrerit imperdiet.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus lobortis nunc sit
amet eros vulputate ac eleifend elit convallis. Quisque commodo erat quis enim tincidunt ac lacinia urna
pretium. Curabitur luctus leo nec turpis sagittis ut porta dui blandit.</p>
<p>Proin nec suscipit nibh. Nulla varius purus et dolor pellentesque ullamcorper. Vestibulum blandit quam et
sapien lobortis blandit. Nulla eu eros lacus, et mattis magna. In lobortis luctus varius. Maecenas in purus
odio, quis porttitor felis. Sed id nisi massa, sit amet placerat magna. Curabitur imperdiet hendrerit imperdiet.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus lobortis nunc sit
amet eros vulputate ac eleifend elit convallis. Quisque commodo erat quis enim tincidunt ac lacinia urna
pretium. Curabitur luctus leo nec turpis sagittis ut porta dui blandit.</p>
<p>Nunc arcu mi, placerat vitae condimentum dapibus, volutpat quis libero. Class aptent taciti sociosqu ad litora
torquent per conubia nostra, per inceptos himenaeos. Suspendisse potenti. Nulla varius erat vel dolor dictum
vestibulum. Quisque adipiscing tincidunt nulla, sed sagittis risus imperdiet sit amet. Donec ultrices tristique
adipiscing. Ut iaculis volutpat mauris. Proin bibendum, diam vel venenatis posuere, felis orci venenatis tortor,
vel egestas nisl tellus accumsan elit. Nullam feugiat odio purus, sed bibendum est. Donec gravida magna sit amet
libero tincidunt ullamcorper.</p>
<p>Nulla facilisi. Ut porttitor semper condimentum. Integer luctus varius nisi, ac condimentum sapien auctor
volutpat. Cras molestie consectetur libero. Phasellus risus urna, imperdiet non porttitor eget, adipiscing
adipiscing magna. Nam semper, felis a condimentum viverra, massa ante varius odio, quis pretium enim neque quis
libero. Nulla massa dolor, imperdiet sed molestie semper, adipiscing at est. Etiam eget quam sed orci vestibulum
ullamcorper. Donec mi sapien, adipiscing in eleifend a, tempor vel velit.</p>
<p>Proin nec su scipit nibh. Nulla varius purus et dolor pellentesque ullamcorper. Vestibulum blandit quam et
sapien lobortis blandit. Nulla eu eros lacus, et mattis magna. In lobortis luctus varius. Maecenas in purus
odio, quis porttitor felis. Sed id nisi massa, sit amet placerat magna. Curabitur imperdiet hendrerit imperdiet.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus lobortis nunc sit
amet eros vulputate ac eleifend elit convallis. Quisque commodo erat quis enim tincidunt ac lacinia urna
pretium. Curabitur luctus leo nec turpis sagittis ut porta dui blandit.</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
test: "hej",
window: null,
lastScrollTop: null,
wasScrollingDown: true,
sidebar: null,
initialSidebarTop: 0,
sideBarFixed: false,
sideBarTop: 0,
};
},
methods: {
handleScroll() {
const windowHeight = window.innerHeight;
const sidebar = document.querySelector('#sidebar');
const sidebarHeight = sidebar.offsetHeight;
var doc = document.documentElement;
var scrollTop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
var scrollBottom = scrollTop + windowHeight;
var sidebarTop = scrollTop + this.sideBarTop;
var sidebarBottom = sidebarTop + sidebarHeight;
var heightDelta = Math.abs(windowHeight - sidebarHeight);
var scrollDelta = this.lastScrollTop - scrollTop;
var isScrollingDown = (scrollTop > this.lastScrollTop);
var isWindowLarger = (windowHeight > sidebarHeight);
if ((isWindowLarger && scrollTop > this.initialSidebarTop) || (!isWindowLarger && scrollTop > this.initialSidebarTop + heightDelta)) {
this.sideBarFixed = true;
} else if (!isScrollingDown && scrollTop <= this.initialSidebarTop) {
this.sideBarFixed = false;
}
var dragBottomDown = (sidebarBottom <= scrollBottom && isScrollingDown);
var dragTopUp = (sidebarTop >= scrollTop && !isScrollingDown);
if (dragBottomDown) {
if (isWindowLarger) {
this.sideBarTop = 0
} else {
this.sideBarTop = (-heightDelta)
}
} else if (dragTopUp) {
this.sideBarTop = 0
} else if (this.sideBarFixed) {
var currentTop = parseInt(this.sideBarTop, 10);
var minTop = -heightDelta;
var scrolledTop = currentTop + scrollDelta;
var isPageAtBottom = (scrollTop + windowHeight >= document.body.offsetHeight);
var newTop = (isPageAtBottom) ? minTop : scrolledTop;
this.sideBarTop = newTop;
}
this.lastScrollTop = scrollTop;
this.wasScrollingDown = isScrollingDown;
},
},
mounted() {
this.lastScrollTop = window.scrollY;
this.wasScrollingDown = true;
const sidebar = document.querySelector('#sidebar');
if (sidebar) {
this.initialSidebarTop = sidebar.offsetTop;
window.addEventListener('scroll', this.handleScroll);
}
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll);
},
};
</script>
<style scoped>
* {
margin: 0;
padding: 0;
}
header {
height: 100px;
background-color: blue;
}
#content {
padding-right: 200px;
background: green;
}
#sidebar {
width: 180px;
padding: 10px;
background: red;
float: left;
}
.fixed {
position: fixed;
}
</style>