ポップアップを背景クリックで閉じるシンプルな方法

背景クリックで閉じるポップアップを実装するシンプルな方法を先輩に教えてもらって個人的に目からウロコだったので共有します。
使うのはHTML、CSS、JavaScriptです。

## 基本的な考え方
- HTML: ラッパーの`div`を作り、その中に背景の`div`とポップアップ本体の`div`を作る
- CSS: ポップアップ本体を背景より小さいサイズにし、`position: absolute;`などで背景の真ん中に来るように位置を調整
- JavaScript: 背景をクリックしたらラッパー全体が隠れるようにする

## イメージ
###　素のHTML
![popup-html.png](https://qiita-image-store.s3.amazonaws.com/0/253501/d125ccdd-04a8-b843-0a5d-7d4f1148ab12.png)

### CSSとJavaScriptで加工後
<img width="1097" alt="popup-drawing.png" src="https://qiita-image-store.s3.amazonaws.com/0/253501/ee94a1db-a7ab-951b-651b-929b510b36d7.png">

## コード

```html
<!DOCTYPE html>
<html>

  <body>
    <button onclick="showPopup()">ボタン</button>  <!--ボタン. クリックでラッパー（とその子要素）見せる. divを使ってもいい-->
    <div class="popup-wrapper is-hidden"> <!--ラッパー.初期状態では隠れている-->
      <div class="popup-background" onclick="hidePopup()"></div> <!--背景. クリックでラッパー(とその子要素)を隠す-->
      <div class="popup-body"></div> <!--ポップアップ本体-->
    </div>
  </body>

  <script>
      /*ポップアップを見せる関数*/
      function showPopup(){  
        var x = document.getElementsByClassName("popup-wrapper"); /*クラス名"popup-wrapper"のオブジェクトの配列を取得*/
        x[0].classList.remove("is-hidden"); /* 最初のオブジェクトが持つCSSクラス("popup-wrapper is-hidden")から"is-hidden"取り除く*/
        }

      /*ポップアップを隠す関数*/
      function hidePopup(){ 
        var x = document.getElementsByClassName("popup-wrapper");
        x[0].classList.add("is-hidden"); /* CSSクラス"is-hidden"を付け足す*/
        }
  </script>

  <style>
      .popup-wrapper {
      width: 100vw; /*画面に大きさを合わせる*/
      height: 100vh;
      position: fixed; /*ラッパーの左上隅を画面左上に固定*/
      top: 0px;
      left: 0px;
      }
      .popup-background{
      width: 100%; /*ラッパー全体を覆うようにする*/
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5); /*半透明の黒*/
      }
      .popup-body{
      width: 50%; /*ラッパーの半分の大きさにする*/
      height: 50%;
      position: absolute; /*ラッパーを基準に、画面中央にくるように調整*/
      top:25%;
      left:25%;
      background-color: white;
      }
      .is-hidden{
        visibility: hidden;
      }
  </style>
  
</html>


```
##目からウロコポイント
- とにかく読みやすい、分かりやすい
- event.targetとかifを使って処理を分ける必要なんてなかったんや

## わざわざラッパーを作るワケ
本体を直接的に背景の子要素にしてしまうと、本体も背景の一部と見なされ、本体をクリックしたときもポップアップが閉じられてしまうからです。（背景と本体は兄弟である必要がある）
他には背景やポップアップの大きさや位置の基準として使えて便利だからです。

## 見せる/隠す方法について
今回は`.is-hidden`というクラスを作り、それをJavaScriptで足したり消したりすることで見せる/隠すを変えました。
`.classList.add("is-hidden")`の代わりに`.style.visibility = "hidden";`や`.style.display = "none";`　を使ってJavaScriptで直接スタイルを書き換えることも可能です。そこらへんはお好みでお願いします。

## 背景とポップアップのサイズと位置調整について

###サイズ
ラッパーの大きさが画面サイズと同じで、背景は親要素（ラッパー）の100%の大きさなので、背景は画面サイズに等しくなります。
ポップアップ本体の50%x50%という大きさもラッパーが基準になっています。

###位置(XY方向）
背景と本体の大きさを整えたところで、どうやって本体を画面の中央に持って来るのか？というと、CSSの`position`プロパティを使います。
今回は`position: absolute`　を使い、`top` と `left` で親要素（ラッパー）の左上隅からの距離を指定することで中央に配置しました。
ですが、実は `position: fixed` や `position:relative` を使うこともできます。

`position: fixed`はざっくり言うと`absolute`に「画面の決まった位置に固定する」という性質を足したものです。 今回は基準となるラッパーがすでに固定されてるので使う意味はありませんが、そのまま`absolute`と置き換えてもレイアウトが崩れません。

`position:relative`は「素」の状態でその要素が存在する場所からの距離で位置を割り出します。今回のポップアップ本体は何もしなければ背景の左下に来ます(冒頭の図を参照)。なので、`relative`で位置を指定する時は背景の左下隅の点を基点にします。%で親要素に対しての割合を示すというところは`absolute`や`fixed`と変わらないので、以下のように書けば同じレイアウトを実現できます。

```css
.popup-body{
      width: 50%;
      height: 50%;
      position: relative; /*背景の左下を基準に、画面中央にくるように調整*/
      top:-75%;
      left:25%;
      background-color: white;
      }
```

###位置(Z方向)
今回のコードだと自然に本体が背景の手前に来ますが、もし本体が背景の裏に入ってしまった時は背景とポップアップ本体のそれぞれに`z-index`を設定すれば大丈夫です。

---
（あとがき）
説明不足や認識に間違いがあるところがあれば訂正していただけると嬉しいです。