How to emulate sticky behavior for position: fixed in Vue2

Although many mobile browsers do not support <position: sticky>
, using position: fixed is not ideal as it can overlap content at the bottom of the document.

I believe that using jQuery to set a static position for the fixed block while scrolling to the bottom of the document would be straightforward.

However, I am unsure of how to achieve the same functionality in Vue2. Any advice or alternative solutions would be greatly appreciated.

Answer №1

As noted in the previous comments, my suggestion would be to utilize a polyfill if feasible since it has been meticulously crafted for precision. However, here is a straightforward approach on how you can achieve this in Vue.

The application manages scroll events by storing the scrollY value in a data item. The sticky-top component determines its fixed top position and applies it if it's greater than 0. The widget utilizes 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>

Answer №2

It appears that this solution is effective for me

...

  <header
    ref="header"
    class="header-container"
    :class="{ 'header-container--sticky': isHeaderSticky }"
  >

...

...

data() {
    return{
      scrollY: null,
      headerTop: 0,
      isHeaderSticky: false,
    }
  },
  mounted() {
    window.addEventListener('load', () => {
      window.addEventListener('scroll', () => {
        this.scrollY = Math.round(window.scrollY);
      });
      this.headerTop = this.$refs.header.getBoundingClientRect().top;
    });
  },
  watch: {
    scrollY(newValue) {
      if (newValue > this.headerTop) {
        this.isHeaderSticky = true;
      } else {
        this.isHeaderSticky = false;
      }
    }
  }

...

...

.header-container {
      &--sticky {
        position: sticky;
        top: 0;
        z-index: 9999;
      }
    }

...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Generating replicated elements at varying positions

After discovering that my previous question, which can be found here, is currently not feasible due to limitations with html2canvas only taking 'snapshots', I have chosen to approach the problem differently. The new approach involves making an o ...

The event emitted doesn't appear to be caught by EventBus.$on in Vue.js

Currently trying to trigger an event from router.beforeEach and listening for it in another component. Although the vue devtool confirms that the event is being triggered, my component seems unable to capture it. Thank you for your help. This is how I dec ...

Transform HTML invoices into emails

I am currently working on developing an ERP system. I have an HTML invoice that needs to be converted into a PDF and sent via email. My question is regarding how to construct the invoice using jQuery & AJAX, convert it into a PDF format, and then send it ...

Using Vue 2 with a personalized Axios setup, integrating Vuex, and incorporating Typescript for a robust

I'm still getting the hang of Typescript, but I'm facing some challenges with it when using Vuex/Axios. Current setup includes: Vue CLI app, Vue 2, Vuex 3, Axios, Typescript At a high level, I have a custom Axios instance where I configure the ...

Searching for a specific element using a CSS selector

Looking for a way to find an element using a CSS selector in Chrome, I followed these steps: Right-click on the object Select "inspect" Right-click on the highlighted area in Chrome developer tools Choose "copy" Click on "copy selector" This is the cod ...

Tips for designing a responsive layout with bordered paragraphs of text

I inserted multiple paragraphs of text into a column. To ensure the text is responsive and surrounded by a border, I created simple HTML code within a div tag: <p> text here</p> <p> 2nd para</p> <p> 3rd para</p> <p&g ...

What are some ways to keep the text within the boundaries of the input box?

How can I prevent the letters from extending beyond the bar when typing a lot of characters? Your assistance in resolving this issue is greatly appreciated. <div id="tasks-container"> <div id="tasks-header"> ...

Troubleshooting a Vue 2 component's prop receiving an incorrect value

I'm currently working on creating a menu that navigates between categories. When a category has a sub-category, it should return a boolean value indicating whether it has a sub-category or not. <template> <select><slot></slot ...

Displaying a progress bar while fetching data in Vue: A step-by-step guide

I am working on developing a progress bar using vue js and bootstrap for my desktop application. Within the template, I have the code that will generate the necessary markup: <div class="container-fluid p-0 vh-100" v-if="isLoading&quo ...

Formatting Specific Labels in HighCharts: A Guide

I'm trying to display the label values within a Highcharts bar chart by utilizing the dataLabels.Formatter function. However, I've noticed that when the bar size is inconsistent, the labels are sometimes displayed inside the bar, which looks goo ...

Display either the Web or Mobile modal upon page load based on the screen size

For my design project, I have crafted two unique modals that will pop up when their corresponding button is clicked. However, I have set it up so that each button is only visible on certain screen sizes using CSS @media query. Now, I am looking to make a ...

It is not possible to rely on Vuex to retrieve data for every single component

Is it possible to fetch data in App.vue and pass the value to this.store.data so that it can be used for all other components? The issue I am facing is that when I click on the link (router-link), the function inside the components runs before fetching dat ...

Animating background color change with scroll in React using fade effect

Can someone help me with implementing a fading animation for changing the background color on scroll in React? I have successfully achieved the background change effect, but I'm struggling to incorporate the fading effect. import React from "reac ...

What is the best way to update props in Vue 3?

Within the main component, I have: <notification-row v-for="(item, index) in notifications" :key="index" :item="item" /> Inside the child component, it looks like this: ... <tr class="notification-row" ...

Creating unique page styles using global styles in Next.js

I am facing a dilemma in my NextJS app. On the /home page, I need to hide the x and y overflow, while on the /books page, I want the user to be able to scroll freely. The issue is that Next only allows for one global stylesheet and using global CSS selec ...

Issues with the Tumblr platform's back-to-top button functionality

I am quite comfortable with HTML and CSS, but I'm struggling to make the 'back to top' button work on my Tumblr page. Can someone please give me a hand? I've included some JQuery code to make the text fade in and out when scrolling (inf ...

Can anyone help me determine the reason why my CSS is being displayed as struck-through in Google Chrome?

After successfully running my app on localhost, I encountered CSS issues when deploying it on Heroku. Some of the CSS appears as struck-through in Chrome. How can I identify what is overriding my styling? https://i.sstatic.net/U23fg.png ...

How to send a function from a parent component to a child component in Vue.js

I'm trying to figure out how to pass the parent component's method to the child component. Here's the scenario: when I click the confirm button on my modal (child component), it needs to send the data from the parent form (parent component). ...

What is the best way to adjust image size based on different screen sizes while ensuring the buttons at the top remain responsive

How can I make the image and image select and delete buttons responsive? I am looking to eliminate the gap after the delete button. Any suggestions are welcomed. <div class="container mt-0"> <div class="row"> ...

What is the best way to include the border-radius CSS property to a dropdown element in Ant Design?

Adding the border-radius CSS property to my dropdown component from ant design has been a bit challenging for me. I attempted to modify the antd-css file and include a style object directly into the component, but unfortunately, I did not achieve the des ...