モーダルの実装から学んでいくHTML・CSS・JS

# 背景

* 雑にコード書いて自分で解説しながらHTMLとCSSとJS少しを勉強する。

# モーダルの構造・要件

- 以下3つのレイヤーからなる。

1. ウィンドウ
1. 背景
1. ダイアログ

## 1. ウィンドウ

- モーダルを開く前に表示されているレイヤー。
- モーダルはこのレイヤーを覆うように表示されることになる。

今回は `body` タグがこれに相当する。

## 2. 背景

- モーダルを開くボタンを押すと、ベースのレイヤーを覆うように表示される薄暗いレイヤー。
- 背景を押すと、モーダルは閉じられる仕様になっていることが多い。
- `overlay` と呼ばれることもある。

今回は `.modal` というクラスで表す。

## 3. ダイアログ

- 背景の上に表示されるレイヤー。
- ここに文章やボタンが表示される。
- 閉じるボタンが併せて表示されていることが多い。

今回は `.modal-content` というクラスで表す。

## 参考リンク

* [【Javascript】Javascript/Cssでモーダルを作ってみた
](https://qiita.com/redrabbit1104/items/1f4c1bf68f8958ec19b5)
* [Modal (モーダル) - Bootstrap
](https://getbootstrap.jp/docs/5.0/components/modal/)
* [Modals - Materialize](https://materializecss.com/modals.html)
* [モーダルとは？モーダルウィンドウの使い方を徹底解説](https://wa3.i-3-i.info/word11432.html)
    * 近年ではUXの観点から、モーダルよりもアコーディオンが推奨みたいな話も書いてあるが一旦スルー。

# 実装と解説

## HTML

```html
<body>
  <div class="container">
    <!-- モーダルを開くボタン -->
    <a class="js-modal-open" href="javascript:void(0);">
      <span>モーダルを開く</span>
    </a>
  </div>

  <!-- モーダル -->
  <div class="modal" id="modal">
    <div class="modal-content" id="modal-content">
      <button class="modal-content__btn-close js-modal-close" type="button">
        <img alt="閉じる" src="icon_close.svg">
      </button>
      <div class="modal-content__body">
        <div>
          <p>
            これがモーダルの中身の文章です。
          </p>
          <button class="js-modal-close" type="button">
            閉じる
          </button>
        </div>
      </div>
    </div>
  </div>
</body>
```

## CSS（SCSS）

```scss
.modal {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 11;
  width: 100%;
  height: 100%;
  background-color: rgba(#000, 0.7);
  overflow: auto;
}

.modal-content {
  position: relative;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 12;
  margin: 30px 20px;
  &__btn-close {
    position: absolute;
    top: -10px;
    right: -10px;
    z-index: 12;
  }
  &__body {
    padding: 20px;
    max-width: 100%;
    max-height: 100%;
    margin: 0 auto;
    background-color: #fff;
    border-radius: 10px;
    overflow: scroll;
  }
}
```

### modal

* `display: none;`
    * 完全にその場にない扱いにする。
    * [display:none と visibility:hidden の違い
](https://qiita.com/rico/items/0f645e84028d4fe00be6)
    * [【CSS】displayの使い方を総まとめ！inlineやblockの違いは？](https://saruwakakun.com/html-css/basic/display)
    * [CSSの display: inline、display: block、display: inline-block をマスターしよう！](https://taneppa.net/display-inline-block/)
        * `block`: widthやheight、marginやpaddingを指定できる。h1、p、divなど。
        * `inline`: blockの中で用いられ、要素を横並びにできる。a、span、strongなど。
            * 例: ulの中でliを横並びにする。
        * `inline-block`: widthやheight、marginやpaddingを指定でき、要素を横並びにできる。
            * 例: ナビゲーションバー、ソーシャルボタン、ページネーションのスタイルを調整し、横並びにする。
* `position: fixed;`
    * ウィンドウ全体を基準として要素を配置する。
    * [CSSのpositionを総まとめ！absoluteやfixedの使い方は？
](https://saruwakakun.com/html-css/basic/relative-absolute-fixed)
        * `absolute`: 親要素の位置を基準として要素を配置する。
        * `relative`: 通常の表示位置を基準として要素を配置する。
* `top: 0; left: 0;`
    * 基準の左上（ = 基準の上からの距離が `0px` 、基準の左からの距離が `0px` の位置）に要素を配置する。
        * [CSSのpositionを総まとめ！absoluteやfixedの使い方は？#2. positionとセットで使うtop・bottom・left・right](https://saruwakakun.com/html-css/basic/relative-absolute-fixed#section2)
* `width: 100%;` 、 `height: 100%;`
    * 親要素の幅に対する比率。
    * [CSSのwidth（幅）とheight（高さ）の指定方法をマスターしよう
](https://saruwakakun.com/html-css/basic/width-height)
    * [[CSS]ビューポート(vw, vh)とパーセント(%)、レスポンシブに適した単位の賢い使い分け方法](https://coliss.com/articles/build-websites/operation/css/viewport-vs-percentage-units-by-ire.html)
        * `vw`: ビューポートの幅に対する比率。
            * 例: ビューポート幅 `320px` のiPhone 5Sの場合、`10vw` : 320/10 = `32px`。
        * `vh`: ビューポートの高さに対する比率。
        * ビューポート:　ブラウザのスクロールバーを含んだサイズのこと。
            * もしページが長く、スクロールバーが表示されているのであれば、ビューポートの幅はhtml要素の幅より大きくなる。
            * ビューポート > html > body。



* `overflow: auto;`
    * コンテンツがパディングボックスに収まる場合 → `overflow: visible;` と同じ。
    * コンテンツがパディングボックスから溢れる場合 → `overflow: scroll;` と同じ。
    * [overflow - MDN Web Docks
](https://developer.mozilla.org/ja/docs/Web/CSS/overflow)
    * [【CSS】overflowの使い方：hiddenやscrollの違いは？](https://saruwakakun.com/html-css/basic/overflow)
        * `visible`: 初期値。はみ出た場合ははみ出たまま表示する。
        * `scroll`: はみ出た部分が隠れ、スクロールにより表示できる。

### modal-content

* `position: relative;`
    * 現在の表示位置から相対的に要素の位置を動かす。
* `top: 0; right: 0; bottom: 0; left: 0;`
    * `top` と `bottom` を同時に `0` に指定すると要素は縦いっぱいに広がる。
    * `left` と `right` を同時に `0` に指定すると要素は横いっぱいに広がる。
    * [CSSのpositionを総まとめ！absoluteやfixedの使い方は？
#2. positionとセットで使うtop・bottom・left・right
](https://saruwakakun.com/html-css/basic/relative-absolute-fixed)

### &__btn-close

* `&`　はSassの親参照セレクタで、出力結果は `modal-content_btn-close` となる。
* `top: -10px; right: -10px;`
* 基準の上からの距離が `-10px` 、基準の右からの距離が `-10px` の位置
    * = 上側に `10px` 、右側 `10px` に突き抜ける。
    * [【CSS】意外と難しい「position」の使い方を詳しく解説してみた
](http://ideahacker.net/2014/02/18/7744/) 

### &__body

* `border-radius: 2px;`
    * 正円の円弧となる半径を指定する。
    * `border` プロパティーの指定がなくても大丈夫。
    * [今さら聞けない!? CSSのborder-radiusで様々な角丸に挑戦！](https://www.webcreatorbox.com/tech/border-radius)
    * [【13-1】borderと borderのショートハンド#borderのプロパティ一覧](http://honttoni.blog74.fc2.com/blog-entry-234.html?sp)

## JavaScript（jQuery）

```js
// ダイアログを開くボタンをクリックした時
$('.modal-open').on('click', () => {
  $('body').css({ 'overflow': 'hidden' });
  $('#modal').show();
  $('#modal-content').show();
});

// ダイアログの外側をクリックした時
$('#modal').off('click').on('click', e => {
  if (e.target !== $('#modal')[0]) { return }

  $('body').css({ 'overflow': '' });
  $('#modal').hide();
  $('#modal-content').hide();
});

// ダイアログの閉じるボタンをクリックした時
$('#modal-content').off('click').on('click', '.js-modal-close', () => {
  $('body').css({ 'overflow': '' });
  $('#modal').hide();
  $('#modal-content').hide();
});
```

* `$('body').css({ 'overflow': 'hidden' });`
    * `body` のコンテンツがスクロールされないように `'overflow': 'hidden'` に変更している。
* `.show()` 、 `.hide()`
    * `css('display', 'block') // デフォルトに戻す` 、 `css('display', 'none')` と同じ。
        * [【jQuery】要素の表示・非表示について (show, hide, toggle)](https://www.task-notes.com/entry/20150112/1420994026)
* `.off()`   
    * 調査範囲内の `on` メソッドによって設定されたイベント発生時の処理を「すべて解除」する。
        * [.off( ) - 設計力を学ぶデザインドリル jQuery入門] (https://www.jquerystudy.info/reference/events/off.html)
    * `unbind` 、 `undelegate` 、`die` を表す。 ※ 要再調査。
        * [jQuery の on() と off() を理解する](https://tacamy.hatenablog.com/entry/2013/03/03/213113)
        * [jQuery 1.7の on() off()について調べてみた
](http://bashalog.c-brains.jp/11/11/08-161217.php)
        * [jQueryのclickとbindとliveとdelegateとonの違い - Qiita](https://qiita.com/smzk/items/5eed5a90c4b32ca8b23a)
            * JavaScriptのイベントの伝搬について詳しい。


# HTML・CSSの前提知識集

* コーディング規約について
    * HTML側
        * JavaScriptで操作したい要素は `id` 属性で指定。
            * [こんなHTMLとCSSのコーディング規約で書きたい
#JavaScript からアクセスする ID とクラス](https://qiita.com/pugiemonn/items/964203782e1fcb3d02c3#javascript-%E3%81%8B%E3%82%89%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B-id-%E3%81%A8%E3%82%AF%E3%83%A9%E3%82%B9)
                * JavaScriptで同じ操作をしたい要素が複数ある場合は、 `js-*` プレフィックスを付けた `class` 属性を指定。
        * `class` 属性は最初にくる。`id` 属性は二番目にくる。
            * [HTMLのタグに属性を書く時に先頭に来るのはidとclassどちらか気になったのでいろいろ見てみた。
](https://qiita.com/ponsuke0531/items/2b15e37b2f46169a1224)
            * [コーディングガイド by @mdo](http://kia-king.com/code-guide/)

    * CSS側
        * [こんなHTMLとCSSのコーディング規約で書きたい
](https://qiita.com/pugiemonn/items/964203782e1fcb3d02c3)
        * [破綻しにくいCSS設計の法則 15
](https://qiita.com/BYODKM/items/b8f545453f656270212a)
            * [CSSが破綻する4つの理由](https://qiita.com/BYODKM/items/8c777db2d89f4e830c93)
        * [CSS設計の基本
](https://qiita.com/tera_shin/items/af90aeba49f93c76bd9e)
* CSSプロパティの記述順について
    * [【CSS】CSSプロパティの記述順について考えてみた
](http://unitopi.com/css-order/)
        * mozilla.org Base Styles というルールがかつては存在していたらしい。が、ネット上のものは大体同じ模様。
    * [メンテナブルCSS](https://megalodon.jp/2015-0724-1340-13/https://www.cyberagent.co.jp:443/techinfo/techreport/report/id=7926)
        * 1.位置情報系(position, top, right, z-index, display, float等)
        * 2.サイズ(width, height, padding, margin)
        * 3.文字系(font, line-height, letter-spacing, color- text-align等)
        * 4.背景(background, border等)
        * 5.その他(animation, transition等)

* CSSのボックスモデルについて
    * [今更聞けない！エンジニアのための CSS の基礎講座 〜ボックスモデル編〜](https://nulab.com/ja/blog/nulab/css-basics-for-engineer-boxmodel/)
    * [CSSのmarginとは？paddingとは？余白の指定方法まとめ](https://saruwakakun.com/html-css/basic/margin-padding)
    * [ボックスモデル - MDN](https://developer.mozilla.org/ja/docs/Learn/CSS/Building_blocks/The_box_model)

* Sassについて
    * [Sassの基本的な書き方をまとめてみた
](https://www.evoworx.co.jp/blog/sass-study/)
    * [Sass(Scss)のよく使う記法まとめ](https://qiita.com/hakshu/items/1f2a164ea0a1a3459119)
    * [Sass公式](https://sass-lang.com/)


* BEMについて
    * [MindBEMding
](https://gist.github.com/juno/6182957)
        * BEM（Block、Element、Modifier）
            * Block: 高レベルに抽象化されたもの。コンポーネント。
                * 例: `.site-search{}`
            * Element: Blockをサポートする子孫をあらわす。
                * 例: `.site-search__field{}` 、 `.site-search__button{}`
            * Modifier: Blockの異なる状態をあらわす。
                * 例: `.site-search--full{}`
                * 今回はハイフン（`-`）1つでModifierをあらわすことにする。
    * [BEMのBlockはElementを入れ子にせずにコンポーネント化しよう](https://www.mk-engineer.com/posts/bem-block-element)
        * > BEMはElementの中にBlockを作っても問題ありません。
        * > HTMLが増えるとBlockの単位が大きくなってしまうので、新たにBlockを作るのがおすすめです。
    * [一番詳しいCSS設計規則BEMのマニュアル](https://qiita.com/Takuan_Oishii/items/0f0d2c5dc33a9b2d9cb1)
    * [細かすぎるけど伝わってほしい私的BEMプラクティス30（ぐらい）](https://necomesi.jp/blog/tsmd/posts/152)
    * [Get BEM#FAQ](http://getbem.com/faq/)
        * 公式のFAQ。
    * [BEMによるフロントエンドの設計 第1回 基本概念とルール](https://www.mk-engineer.com/posts/bem-block-element)
        * > Blockはどこにでも置くことができ、Blockの中にBlockを含めることも可能です。ただし、CSSではBlockを入れ子にしてスタイルを指定してはいけません。

```html
<!-- BEMを使った例 -->
<form class="site-search site-search--full">
    <input type="text" class="site-search__field">
    <input type="Submit" value ="Search" class="site-search__button">
</form>
```

# おまけ（発展）

* HTMLのアクセシビリティについて
    * [HTML: アクセシビリティの基礎](https://developer.mozilla.org/ja/docs/Learn/Accessibility/HTML)
    * [freeeアクセシビリティー・ガイドライン](https://a11y-guidelines.freee.co.jp/)
    * [Webのアクセシビリティを向上させる、始めに取り組んでおきたいガイドラインの10項目のまとめ](https://coliss.com/articles/build-websites/operation/work/guidelines-to-improve-web-accessibility.html)
    * [Webアクセシビリティ 逆引きガイドライン](https://weba11y.jp/know-how/guidelines/guidelines_index/)

* CSSの構造化について
    * [FLOCSS](https://github.com/hiloki/flocss)

```shell
# Sassを採用した場合のFLOCSSによるディレクトリ構成
├── foundation
│   ├── _base.scss
│   └── _reset.scss
├── layout
│   ├── _footer.scss
│   ├── _header.scss
│   ├── _main.scss
│   └── _sidebar.scss
└── object
    ├── component
    │   ├── _button.scss
    │   ├── _dialog.scss
    │   ├── _grid.scss
    │   └── _media.scss
    ├── project
    │   ├── _articles.scss
    │   ├── _comments.scss
    │   ├── _gallery.scss
    │   └── _profile.scss
    └── utility
        ├── _align.scss
        ├── _clearfix.scss
        ├── _margin.scss
        ├── _position.scss
        ├── _size.scss
        └── _text.scss
```