Creating a sidebar and content container that share scroll with sidebar sticking to top and bottom

Viewed 25

I am trying to create a layout with a sidebar container and a content container where both of them are overflowing and when you scroll the page it scrolls both of the containers simultaneously. The sidebar should snap to the top/bottom of the screen when you scroll. Its a bit hard to explain but its implemented on this page perfectly: https://www.kiwi.com/sv/sok/results/lulea-sverige/stockholm-sverige

What is the best way to implement this? I am trying to create states for the sidebar top | middle | bottom where middle is relative and top and bottom are fixed. Trying to use intersection API & the scroll event to detect which state we're in. But I'm not sure using scroll event is optimal because of performance.

Here is my attempt at implementing it: https://codesandbox.io/s/vue-2-playground-forked-wsm9gd?file=/src/components/SidebarAndContent.vue

Its not working great and I would love some input on the best way to do this. Thanks!

2 Answers

this suppose to solve you problem if i get it correctly`

body {
  font-family: "Lato", sans-serif;
}

.sidenav {
  height: 100%;
  width: 160px;
  position: fixed;
  z-index: 1;
  top: 0;
  left: 0;
  background-color: #111;
  overflow-x: hidden;
  padding-top: 20px;
}

.sidenav a {
  padding: 6px 8px 6px 16px;
  text-decoration: none;
  font-size: 25px;
  color: #818181;
  display: block;
}

.sidenav a:hover {
  color: #f1f1f1;
}

.main {
  margin-left: 160px; /* Same as the width of the sidenav */
  font-size: 28px; /* Increased text to enable scrolling */
  padding: 0px 10px;
}

@media screen and (max-height: 450px) {
  .sidenav {padding-top: 15px;}
  .sidenav a {font-size: 18px;}
}
<body>

<div class="sidenav">
  <a href="#about">About</a>
  <a href="#services">Services</a>
  <a href="#clients">Clients</a>
  <a href="#contact">Contact</a>
</div>

<div class="main">
  <h2>Sidebar</h2>
  <p>This sidebar is of full height (100%) and always shown.</p>
  <p>Scroll down the page to see the result.</p>
  <p>Some text to enable scrolling.. Lorem ipsum dolor sit amet, illum definitiones no quo, maluisset concludaturque et eum, altera fabulas ut quo. Atqui causae gloriatur ius te, id agam omnis evertitur eum. Affert laboramus repudiandae nec et. Inciderint efficiantur his ad. Eum no molestiae voluptatibus.</p>
  <p>Some text to enable scrolling.. Lorem ipsum dolor sit amet, illum definitiones no quo, maluisset concludaturque et eum, altera fabulas ut quo. Atqui causae gloriatur ius te, id agam omnis evertitur eum. Affert laboramus repudiandae nec et. Inciderint efficiantur his ad. Eum no molestiae voluptatibus.</p>
  <p>Some text to enable scrolling.. Lorem ipsum dolor sit amet, illum definitiones no quo, maluisset concludaturque et eum, altera fabulas ut quo. Atqui causae gloriatur ius te, id agam omnis evertitur eum. Affert laboramus repudiandae nec et. Inciderint efficiantur his ad. Eum no molestiae voluptatibus.</p>
  <p>Some text to enable scrolling.. Lorem ipsum dolor sit amet, illum definitiones no quo, maluisset concludaturque et eum, altera fabulas ut quo. Atqui causae gloriatur ius te, id agam omnis evertitur eum. Affert laboramus repudiandae nec et. Inciderint efficiantur his ad. Eum no molestiae voluptatibus.</p>
</div>
   
</body>

`

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>
Related