HTML CSSのみ使用のポップアップ表示テンプレート

# モチベーション
HTMLとCSSの練習として，各画面の共通機能であるポップアップをある程度テンプレート化してみたいと感じた．
ついでに，ポップアップ表示用のボタンのデザインも少し遊んでみた．

# 実際の動作
各ボタンごとに異なるデザインのポップアップが適応されています．ポップアップ右上の×ボタンまたはポップアップ外の領域をクリックで閉じることができます．
<p class="codepen" data-height="500" data-default-tab="html,result" data-slug-hash="ExqYpMO" data-pen-title="popup" data-user="bhrnuexv-the-solid" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/bhrnuexv-the-solid/pen/ExqYpMO">
  popup</a>(<a href="https://codepen.io/bhrnuexv-the-solid">@bhrnuexv-the-solid</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# 解説
ポップアップをテンプレ化するために以下の要素に注目しました．
1.  ポップアップの閉じ方
2.  ポップアップ数の拡張性
3.  デザインのカスタム性

ポップアップは最小で以下のHTML(+CSS)で実現できます．
チェックボックスの入力有無をCSSの要素指定で取得して（[CSSの要素指定方法メモ](#-CSSの要素指定方法一覧)）ポップアップの表示を切り替えているため，チェックボックスに紐付けたlabel要素さえ作成すればどこからでもポップアップを開くことができます．




```html:最小構成
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /*popup template design*/
    .popup-background{
        /*position size*/
        position: fixed;
        z-index : 100;
        top : 0;
        left : 0;
        height : 100vh;
        width : 100vw;

        /*design*/
        background-color: gray;
        opacity : 0.5
    }
    .popup{
        /*position size*/
        --height : 300px;
        --width : 300px;
        z-index : 101;
        position: fixed;
        top : calc(50vh - calc(var(--height) / 2));
        left : calc(50vw - calc(var(--width) / 2));
        height : var(--height);
        width : var(--width);

        /*design*/
        overflow: hidden;
        background-color: white;
        border-radius: 10px;
        box-shadow: 0px 0px 3px 1px gray;
    }
    .popup > .close-button{
        /*position size*/
        --size : 20px;
        position:absolute;
        top : calc(var(--size)/4);
        left : calc(var(--width) - var(--size) * 5/4);/*css variables are available in children*/
        height : var(--size);
        width : var(--size);

        /*design*/
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: transparent;
        color : gray;
        font-size: var(--size);
        border-radius: calc(var(--size)/5);
    }
    .popup > .close-button:hover{
        /*design*/
        background-color: red;
        color : white;
    }
    .popup > .content{
        padding: 10px;
        text-align: center;
    }
    

    /*hide popup*/
    .popup-flag{
        display:none;
    }
    .popup-flag:not(:checked) + .popup-background{
        display:none;
    }
    .popup-flag:not(:checked) + * + .popup{
        display:none;
    }



  
  </style>

</head>

<body>
    <!--popup-open-button-->
    <label for="popupFlag1">Popup 1</label>


    <!--popup-template-->
    <input type="checkbox" class="popup-flag" id="popupFlag1">
    <label class="popup-background" for="popupFlag1"></label>
    <div class="popup">
        <label class="close-button" for="popupFlag1">×</label>
        <div class="content">
            <h3>Popup 2</h3>
            <h5>new popup</h5>
        </div>
    </div> 

</body>
</html>
```

### ①ポップアップの閉じ方
個人的なポップアップの閉じ方の理想が右上の×ボタンとポップアップ外のクリックだったため，チェックボックスに紐付けたlabel要素を2つ用意してそれぞれポップアップの背景と×ボタンとしました．
背景のlabel要素にはpopup-backgroundクラスを持たせており，CSS側で画面サイズ最大に表示するように設定しています．×ボタンのlabel要素にはclose-buttonクラスを持たせており，CSS側でポップアップの右上に常時配置されるように設定しています．

### ②ポップアップ数の拡張性
先程の最小構成テンプレートの中のポップアップのHTML要素をコピーして，idとforのみ変更することで新しいポップアップを追加することができます．
ポップアップごとにデザインを変更する場合は，次節③デザインのカスタム性にてやり方を解説しています．
```html
<!--popup-template-->
<input type="checkbox" class="popup-flag" id="popupFlag1">
<label class="popup-background" for="popupFlag1"></label>
<div class="popup">
    <label class="close-button" for="popupFlag1">×</label>
    <div class="content">
        <h3>Popup 1</h3>
        <h5>big</h5>
    </div>
</div> 

<!--new popup-->
<input type="checkbox" class="popup-flag" id="popupFlag2">
<label class="popup-background" for="popupFlag2"></label>
<div class="popup">
    <label class="close-button" for="popupFlag2">×</label>
    <div class="content">
        <h3>Popup 1</h3>
        <h5>big</h5>
    </div>
</div> 
```

### ③デザインのカスタム性
テンプレートのCSS記述の下に追加していくことで，上書きする形でデザインを変更することができます．
#### 基本的なデザイン調整
ポップアップの縦幅・横幅はクラスpopup内のCSS変数--height・--widthに対応しています．
そのためポップアップ表示用のinputのidを元に変更したいpopupクラスを指定して，--heightと--widthを変更することで，元のテンプレートを触らずに追加のみでデザインを調整することができます．（位置は自動で中央に設定されます！）
同様に追記することで，色やその他デザインも調整可能です．
```css:ポップアップの大きさ
#popupFlag2 + * +.popup{
  /*position size*/
  --height : 150px;
  --width : 150px;
}
```
また，popup内の×ボタンを除いた中身のみデザイン変更したい場合は，popupクラス内のcontentクラスを指定することでお好みでデザインできます．

```css:ポップアップの中身だけ
.popup > .content{
  padding: 10px;
  text-align: center;
}
```


#### アニメーション付与
ポップアップ開閉時のアニメーションを付ける際にはもう少し追加が必要になります．
重要な点は#popupFlag3 + * +.popup内のdisplay:blockの指定です．テンプレートの状態ではdisplay:noneでポップアップの表示を切り替えているため，アニメーションが付かずに即座に表示が切り替わってしまいます．
display:blockの指定ができたら，#popupFlag3 + * +.popupに表示後のデザイン，#popupFlag3:not(:checked) + * + .popupに表示前のデザインを設定することでアニメーションを付与することができます．

```css:ポップアップのアニメーション
#popupFlag3 + * +.popup{
  /*position size*/
  --height : 150px;
  --width : 350px;

  /*design*/
  display:block;
  transform: rotate(30deg);
  box-shadow: 0px 0px 3px 1px gray;
  transition: 0.5s;
}
#popupFlag3:not(:checked) + * + .popup{
  /*position size*/
  --height : 0px;

  /*design*/
  transform: rotate(0deg);
  box-shadow: 0px 0px 0px gray;
}
```

# 感想
CSSの勉強になって楽しかったです．
ただ，実際の開発ではJS無しで縛る必要はないと思うので，どうしてもHTMLとCSSのみで作りたいって人やCSSを練習したいって人に届けば嬉しいと思いました．

# CSSの要素指定方法一覧

| header     | ヘッダー      |
|:-----------|------------|
| スペース無し | 全指定を含む要素．div.a#aであればクラス"a"とid"a"を持つdivタグを指定．       |
| 半角スペース     | **全子要素**の中で指定を含む要素（子要素の深さは問わない）．div .a #aであればdivタグ内のクラス"a"を持つ子要素の中のid"a"を持つ子要素を指定． |
| ">"   | **直下の子要素**の中で指定を含む要素．div > .aであればdivタグ直下のクラスaを持つ要素を指定．    |
| "+" | **同階層で直後の要素**．div + .aであればdivタグ直後のクラスaを持つ要素を指定． |
| "~" | **同階層で自身以降全ての要素**．div ~ .aであればdivタグ以降に記述したクラスaを持つ要素を全て指定． |
| :hover | 要素の上にマウスカーソルを持ってきた場合のみ反応．div:hover |
| :checked | チェックボックスやラジオボタンなどの要素が入力された時のみ反応．input:checked   |
| :active | 要素がクリックされた時のみ反応．label:active |
| :not() | ()内に記述した要素が存在しないときに反応．input:not(:checked)でがあればinputが未入力の場合を指定． |
| :has() | ()内に記述した要素が存在するときに反応．div:has(>input:checked)であればdiv直下のinput要素が入力済みであればdivを指定．<br>子要素の有無を判定しつつも親要素の場所をメインにしておきたい場合などに使える．例えばbody:has(#popupFlag:checked) #popupと指定すれば，bodyタグ内の#popupFlagと#popupの位置が離れていたとしても#popupの表示を切り替えることができる．|
| child系 | 子要素を番号で指定可能．#a > div:nth-child(2)であればid"a"を持つ要素の直下の二番目のdivタグを指定．上手く使うと要素が１個だけの時や特定の数ある時を判定することもできる． |