vueでBody Scroll Lockの使い方(モーダルウィンドウ時に背景固定でスクロールさせない)

プログラミング学習

モーダルウィンドウ時に背景固定でスクロールさせない方法を調べて実装しました。

モーダルウィンドウ時に背景固定でスクロールさせない

よくモーダルウィンドウを開いた際に、背景固定でスクロールさせない方が良い場合があります。

軽く調べたところ2つのプラグインがでてきました。

Body Scroll Lockとv scroll lockの評判

ダウンロード数や更新日をみるとBody Scroll Lockがよさそうです。

評判はよいようです。

少し気になります。

iOS の Safari問題

スクロールさせない実装は他にもありますが、Safari問題があるようです。

スポンサーリンク

実装!vueでBody Scroll Lockの使い方:vue(nuxt)で背景をスクロールさせない)

nuxtの場合、mountedに指定します。インポートして次のようなコードを書くと画面が固まります。

  mounted() {
    this.modal = document.querySelector('.window')
    disableBodyScroll(this.modal)
  }

実際にはモーダルウィンドウだけ子コンポーネント化して親子のやりとりが必要そうです。でないと固まってしまうので。

<script>
import { disableBodyScroll, enableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock'

export default {
  data() {
    return {
      modal: null
    }
  },
  mounted() {
    this.modal = document.querySelector('.window')
    disableBodyScroll(this.modal)
  },
  beforeDestory() {
    clearAllBodyScrollLocks()
  },
  methods: {
    closeModal() {
      enableBodyScroll(this.modal)
      this.$emit('close')
    }
  }
}
</script>

ちゃんと再読み込みしないと反映されないようなので要注意。

vueでモーダルウィンドウにおけるabsoluteとfixedの違い

モーダルウィンドウを開いたとき、よく黒背景を画面全体に敷きます。

しかしabsoluteを使うとコンポーネントのテンプレート単位のabsoluteになってしまうようです。要はコンポーネントの単位でしか暗くなりません。というわけでこうなりました。

.modal-background {
  /* position: absolute; */
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  cursor: pointer;
  background-color: rgba(0, 0, 0, 0.7);
}

モーダルウィンドウのz-index

ちょっとよく考えた方がよいかもですね。

要素にpositionが定義されているか、z-indexの番号が正しい順序であるか、を確認する。

子要素のz-indexレベルを制限する親要素がないことを確認する。

https://coliss.com/articles/build-websites/operation/css/4-reasons-z-index-isnt-working.html

【解決済】iPhoneでモーダルウィンドウ閉開時にスクロールしてトップに戻る問題【ios12で検証】

しかし、iosの問題はこれだけでは解決しません。

固定する問題とモーダルウィンドウ が開いたとき、
スクロールしてトップに戻る問題は別問題のようです。
最初、body-scroll-lockで全部解決するものかと😓

試したところ、body-scroll-lockでは後者は解決しません。
モーダルウィンドウ が開いたとき、bodyにスタイルを付与します。

document.body.style.top = -${window.scrollY}px;
this.scrollValue = document.body.style.top

閉じるときは少々複雑です。

loses its scroll position

https://css-tricks.com/prevent-page-scrolling-when-a-modal-is-open/

開いたときに座標を失われています。つまり再取得した上で元に戻す必要があるようです。

closeModal() {
    this.preventScrollTop()
    enableBodyScroll(this.modal)
},
preventScrollTop() {
    // const scrollY = document.body.style.top //なぜか取得できない場合がある。。
    const scrollY = this.scrollValue
    document.body.style.top = ''
    window.scrollTo(0, parseInt(scrollY || '0') * -1)
}

今回、解決に貢献した記事は引用先にあるおなじみのcss-tricksさんです。ありがとうございます。

ただ、css-tricksさんの記事そのままではうまくいかず結局一工夫しました。scrollYがうまく取得できない場合(取得できる場合もある)があり、そのため最終的に変数で持たせるようにしました。

また最初モーダルが開いたときの黒背景をひきました。この黒背景をクリックしても閉じれます。この黒背景が親コンポーネントにあったのですが、黒背景をクリックして閉じたときスクロール(データのやりとりをしても)したため、全部子コンポーネントに入れました。

この作業は1番めんどくさかったです。。難しいというより面倒なだけ😓

スポンサーリンク

Body Scroll Lockのエラー

ターゲットの指定が間違っていただけでした。凡ミスです。

bodyScrollLock.esm.js:180 disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.

classの指定でドットが抜けているとでるようです。

this.modal = document.querySelector('window')

またこのエラーはwatchで監視するととなぜかこのエラーがでましたね。mountedはでません。おそらく何かしらおかしな使い方をするとでるのかもしれません。

スポンサーリンク

モーダルウィンドウ時に背景固定でスクロールさせない(CSS制御による別の方法)

以前、試した別の方法も覚書程度に残しておきます。ポイントは次のコードです。

touch-action: none;

https://benfrain.com/preventing-body-scroll-for-modals-in-ios/

引用先の議論を参考にしました。

あとはJavascrpt側からbodyタグにclassの追加と削除をしてあげます。開くタイミングと閉じるタイミングでコールすればいいだけです。

document.body.classList.remove('modal-active')
document.body.classList.remove('modal-active')

modal-activeのclassでtouch-action: none;をしているわけです。

ただ、iPhoneでスクロールしてトップに戻る問題は別問題ですので、そちらの対応も必要です。対応方法は上記のとおりです。

スポンサーリンク

モーダルウィンドウとは(メリット/デメリット/使いどころ)

モーダルウィンドウとポップアップの違い

モーダルウィンドウとポップアップは同じような意味で使っている人もいますが、モーダルウィンドウは固定でプログラミング的には黒背景をひくことにより他のボタンを押せなくしています。

ポップアップは他の操作もできるものですかね。ゲームとかで閉じずに他の操作が可能で横に移動しておくものもありますよね。

モーダルウィンドウは中央位置で開くことが多いが、違うものの場合、スクロール時にポップアップを隅っこで開いてもボタンが押せて戻れなくてはいけない。

モーダルウィンドウのデメリット・メリット

  • メリットは画面遷移がいらない。
  • 普通のウィンドウ(ページ送りがついたポップアップ等もある)の場合、面積が決まるので情報量が少ない場合が多い。
  • エラー、警告、ロード、はい・いいえの確認などで使える。
  • 個人的にやめてほしいモーダルウィンドウはセールスや広告。あれだけは無意味。。。毎回でてくるアプリは最悪のユーザビリティでしょう。広告は主張せずユーザーが主体的にクリックしたいとき意外でしゃばってはいけません。謙虚な姿勢が大事。

参考になれば幸いです。

コメント

タイトルとURLをコピーしました