Search code examples
cssvue.jsvuejs2css-positionsticky

Make position: fixed behavior like sticky (for Vue2)


Position: sticky doesn't support by the most mobile browsers. But position: fixed is not that thing I need (because of fixed block overlaps content in the bottom of document).

I guess for jquery it will be easy to set static position for fixed block if we get bottom of document onscroll.

But for Vue2 I haven't any idea how to do the same. Give some advice please. Or maybe better solution exists.


Solution

  • As I mentioned in the comments, I'd recommend using a polyfill if at all possible. They will have put a lot of effort into getting it right. However, here is a simple take on how you might do it in Vue.

    I have the application handle scroll events by putting the scrollY value into a data item. My sticky-top component calculates what its fixed top position would be, and if it's > 0, it uses it. The widget is position: relative.

    new Vue({
      el: '#app',
      data: {
        scrollY: null
      },
      mounted() {
        window.addEventListener('scroll', (event) => {
          this.scrollY = Math.round(window.scrollY);
        });
      },
      components: {
        stickyTop: {
          template: '<div class="a-box" :style="myStyle"></div>',
          props: ['top', 'scrollY'],
          data() {
            return {
              myStyle: {},
              originalTop: 0
            }
          },
          mounted() {
            this.originalTop = this.$el.getBoundingClientRect().top;
          },
          watch: {
            scrollY(newValue) {
              const rect = this.$el.getBoundingClientRect();
              const newTop = this.scrollY + +this.top - this.originalTop;
    
              if (newTop > 0) {
                this.$set(this.myStyle, 'top', `${newTop}px`);
              } else {
                this.$delete(this.myStyle, 'top');
              }
            }
          }
        }
      }
    });
    #app {
      height: 1200px;
    }
    
    .spacer {
      height: 80px;
    }
    
    .a-box {
      display: inline-block;
      height: 5rem;
      width: 5rem;
      border: 2px solid blue;
      position: relative;
    }
    <script src="//unpkg.com/vue@latest/dist/vue.js"></script>
    <div id="app">
      <div class="spacer"></div>
      <div class="a-box"></div>
      <sticky-top top="20" :scroll-y="scrollY"></sticky-top>
      <div class="a-box"></div>
    </div>