移動端滾動穿透問題解決方案

Logan70發表於2018-10-22

一、 問題描述

移動端當position:fixed的彈窗彈出時,滑動彈窗,下層的頁面會跟隨滾動

二、 解決方案

1. body 設定overflow: hidden;

當彈窗彈出時,設定body元素的overflow屬性為hidden,暴力去除滾動。

缺點:會丟失頁面的滾動位置,需要使用js進行還原

// CSS
.modal-open {
  overflow: hidden;
  height: 100%;
}
複製程式碼
// JS
let modalManager = (function() {
  return {
    scrollTop: 0,
    getScrollTop() {
      return document.body.scrollTop || document.documentElement.scrollTop
    },
    scrollTo(position) {
      document.body.scrollTop = document.documentElement.scrollTop = position
    },
    show(ele) {
      this.scrollTop = this.getScrollTop()
      document.querySelector(ele).style.display = 'block'
      document.body.classList.add('modal-open')
      this.scrollTo(this.scrollTop)
    },
    hide(ele) {
      document.querySelector(ele).style.display = 'none'
      document.body.classList.remove('modal-open')
      this.scrollTop = 0
    }
  }
})();
複製程式碼

2. body 設定position: fixed;

當彈窗彈出時,設定body元素的positon屬性為fixed,使其脫離文件流,去除滾動。

缺點:會丟失頁面的滾動位置,需要使用js進行還原

// CSS
.modal-open {
  position: fixed;
  width: 100%;
}
複製程式碼
// JS
let modalManager = (function() {
  return {
    scrollTop: 0,
    // 彈窗數量
    modalNum: 0,
    getScrollTop() {
      return document.body.scrollTop || document.documentElement.scrollTop
    },
    // body脫離文件流,通過設定其top屬性來恢復滾動位置
    scrollTo(position) {
      document.body.style.top = -position + 'px'
    },
    show(ele) {
      // 與第一種方法不同的是,body脫離文件流時,讀取不到scrollTop,所以同時彈出多個彈窗的時候,不用重新讀取scrollTop
      if (this.modalNum <= 0) {
        this.scrollTop = this.getScrollTop()
        document.body.classList.add('modal-open')
        this.scrollTo(this.scrollTop)
      }
      document.querySelector(ele).style.display = 'block'
      this.modalNum++
    },
    hide(ele) {
      if (this.modalNum <= 1) {
        document.body.classList.remove('modal-open')
        document.body.scrollTop = document.documentElement.scrollTop = this.scrollTop
        this.scrollTop = 0
      }
      document.querySelector(ele).style.display = 'none'
      this.modalNum = this.modalNum >= 1 ? this.modalNum - 1 : 0
    }
  }
})();
複製程式碼

3. 阻止彈窗的touchmove預設事件

缺點:導致彈窗內部也無法滾動,適用於彈窗內無滾動內容的情況

document.querySelector('.modal').addEventListener('touchmove', e => {
  e = e || window.event
  e.preventDefault()
}, false)
複製程式碼

相關文章