Javascriptでモーダルウィンドウを実装する

2022/12/22に公開

introduction

今回は、モーダルウィンドウを仕事で作成するため、せっかくなら記事にしてみようということでこれを作った。別に初心者にわかりやすい説明とかはする気がないけど、普通のエンジニアが読んだらわかるわ〜くらいにはしたいな。

そもそもモーダルウィンドウとは?

モーダルウィンドウってのは、一言でいうと”そのウィンドウが開いている間は他の操作をさせないようなウィンドウのこと”をいう。ただ、それがなんでmodal windowなんて呼ばれているのには気にならないか?それについて見てみよう。googleで「modal meaning」なんて検索していると、以下の文が出てくるのではないだろうか。
relating to mode or form as opposed to substance.
つまり物質とは反対に、モードや形といった曖昧な概念のことをmodalというみたい。このモードというのに着目するとmodal windowは理解しやすい。例えばこのモーダルウィンドウが開いた状態は、そのサイトは別の状態(モード)に入ったと解釈すると、モーダルウィンドウの名が体を表しているようにきこえてきたんじゃないか?ま、聞こえなかったら自分で別の理解法を探して理解してくれや。

htmlについて

とりあえず必要なのは、モーダルウィンドウを開くためのボタンとウィンドウ、そしてウィンドウの背景が暗くなるようにするdiv。簡易的に以下のようにする。モーダルウィンドウを上下左右真ん中に配置するためにインナーをおいている(display:fixとflexは両立できないため)。bufferはまじであってもなくてもいい。今回置いているのはスクロールがされないということを確認するためにおいている。


  <button  class="button modalOpen">Click Me</button>
  <div class="modal">
    <div class="modal-inner">
    <div class="modal-content">
      <div class="modal-header">
        <h1>windowを開きました</h1>
        <span class="modalClose">×</span>
      </div>
      <div class="modal-body">
        <p>どやぁ</p>
      </div>
    </div>
    </div>
 </div>
    <div class="buffer"></div>

cssについて

ボタンを作成するためのcssとモーダルウィンドウを表示したあとのcssが必要。displayにはnoneをおいているが、キーフレームを用いることによってアニメーションが可能になる。

body {
  font-family: serif;
  font-size: 16px;
  line-height: 1.6;
  color: #fff;
  
}
body.open{
  overflow-y:hidden;
}

/* ボタン */
.button {
  background: lightblue;
  color: #fff;
  padding: 0 2em;
  border: 0;
  width: 500px;
  height: 100px;
  font-size: 45px;
  border-radius: 5px;
  font-weight: 900;
  position: relative;
  left: 400px;
  top: 260px;
  font-family: serif;
}

.button:hover {
  background: lightcoral;
  cursor: pointer;
}

/* モーダル */
.modal {
  display: none;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  height: 100vh;
  height:100dvh;
  width: 100%;
  overflow: auto;
  background-color: rgba(0,0,0,0.5);
  
}
.modal-inner{
  height:100%;
  display:flex;
  justify-content:center;
  align-items:center;
}
.modal-content {
  background-color: #f4f4f4;
  width: 50%;
  box-shadow: 0 5px 8px 0 rgba(0,0,0,0.2),0 7px 20px 0 rgba(0,0,0,0.17);
  animation-name: modalopen;
  animation-duration: 1s;
}

@keyframes modalopen {
  from {opacity: 0}
  to {opacity: 1}
}

.modal-header h1 {
  margin: 1rem 0;
}

.modal-header {
  background: lightblue;
  padding: 3px 15px;
  display: flex;
  justify-content: space-between;
}

.modalClose {
  font-size: 2rem;
}

.modalClose:hover {
  cursor: pointer;
}

.modal-body {
  padding: 10px 20px;
  color: black;
}

.buffer{
  height:300vh;
}

jsについて

必要なのは、ボタンを押したら開く機能、閉じるボタン、そしてウィンドウ外を押すと閉じる機能。
以下にそれを書いておく。

const buttonOpen = document.getElementsByClassName('modalOpen')[0];
const modal = document.getElementsByClassName('modal')[0];
const buttonClose = document.getElementsByClassName('modalClose')[0];
const body = document.getElementsByTagName('body')[0];
// ボタンがクリックされた時
buttonOpen.addEventListener('click', function(){
  modal.style.display = 'block';
  body.classList.add('open');
});


// バツ印がクリックされた時
buttonClose.addEventListener('click',function(){
  modal.style.display = 'none';
  body.classList.remove('open');
});

// モーダルコンテンツ以外がクリックされた時
modal.addEventListener('click', function(){ 
    modal.style.display = 'none';
    body.classList.remove('open');
});

スクロール禁止

先述したのでもしかしたら気づいている人もいるかも知れないが、bodyに対してoverflow-y:hiddenを当てるとスクロールが禁止される。bodyにoverflowを当てると、それはそのままビューポートに適用されることがこのテクニックの肝になっているのだが、これは以下のサイトがためになる。
https://ja.stackoverflow.com/questions/54458/body-に-overflowhidden-をあてるとなぜスクロールしなくなるのでしょうか

実装後

終わりに

スクロール禁止の実装とか、またまた学ぶ内容が多かった。面白いよね。javascript。

Discussion