(Vue.js) Scrolling in the modal will also scroll the back of the modal

12,848

Solution 1

Most modal packages solve this by applying a class to the <body> tag when a modal is opened. For example, <body class="modal-open">. Then in your application's CSS, you can add this rule:

body.modal-open {
  overflow: hidden;
}

This will make it so that the page behind the modal is no longer scrollable.

Whichever modal package you are using likely fires events when the modal is opened or closed. You can apply this class to the <body> tag in the open event handler, and remove the class from the <body> tag in the close event handler.


UPDATE

Based on the code you added, here's how you can toggle the modal-open class on the <body> tag:

...

<div @click="showModal(item)" style="cursor:pointer;">
  <img :src="item.thumbnail" />
</div>
<Modal v-if='item.show' @close="hideModal(item)">
  <div slot='body'>
    <img :src="item.thumbnail" :class="`img-index--${index}`"/>
  </div>        
</Modal>

...

{
...

methods: {
  showModal(item) {
    item.show = true
    document.body.classList.add("modal-open");
  },
  hideModal(item) {
    item.show = false;
    document.body.classList.remove("modal-open");
  }
},

...
}

See this jsFiddle for reference.

Solution 2

I can't see your specific code running, but you can generally fix this by setting the body of your page to "overflow:hidden" when you open your modal. To make it more elegant, check to see if the page has scrollbars and add some margin to the right side to prevent content shift. I've used this scrollbar detection in the past, but I'd strip it down to the bare minimum if I used it today... I no longer care about old IE.

Share:
12,848
ddon
Author by

ddon

:)

Updated on June 27, 2022

Comments

  • ddon
    ddon almost 2 years

    Clicking on the image brings up a long, scrolling modal. The problem is that if you scrolling in the modal will also scroll the back of the modal. How do you solve it?

    Modal is a component. Here is my code:

    Carousel.vue

    <template>
      <div>
        <div v-for="(item, index) in photos" :key="index">
          <div @click="imgClick(item)" style="cursor:pointer;">
            <img :src="item.thumbnail" />
          </div>
          <Modal v-if='item.show' @close="item.show = false">
            <div slot='body'>
              <img :src="item.thumbnail" :class="`img-index--${index}`"/>
            </div>        
          </Modal>
        </div>
      </div>
    </template>
    
    <script>
    import Modal from './Modal.vue'
    export default {
      props: {
        items: { type: Array, default: () => [] }
      },
      data() {
        return {
          photos: {}
        }
      },
      created() {
        this.photos = this.items.map(item => {
          return { ...item, show: false }
        })
      },
      methods: {
        imgClick(item) {
          item.show = true
        }
      },
      components: {
        Modal: Modal
      }
    }
    </script>