ズレないCSSを書くために、気をつけたい2つのポイント

# 概要

昨今ではマルチデバイスに対応するため、レスポンシブデザインとして様々な画面サイズに対応する必要が出ています。
ただ、CSSを何となく書くとズレてしまいがちなので、経験的に意識したほうが良いと思う2点をまとめました。

※特定のフレームワークに依存した話ではないので生のHTMLで書いています。コンポーネントやテンプレートなどでの生成結果だと思ってください。

## ポイント1: 自身の外側に干渉するようなスタイルを書かない

各部品は、外側に対する指定を持たせてはいけません。
一番多い例は`margin`だと思われます。

```html
  <div class="form">
    <label class="checkbox"><input type="checkbox" class="checkbox_input">ラベル1</label>
    <label class="checkbox"><input type="checkbox" class="checkbox_input">ラベル2</label>
  </div>
```

```scss
  /** 利用側の定義 **/
  .form {
    display: flex;
    flex-direction: column;
  }

  /** 部品側の定義 */
  .checkbox {
    margin-left: 10px;
    display: flex;
    align-items: center;
  }
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/281108/bcad9cac-a51e-ae6c-5721-bb9c3ede6024.png)


チェックボックス部品が縦に複数並んでいる例です。
左端に接しないようにmarginを設定するのはよくある例ですが、この書き方では__常に左余白が10pxある箇所でないと使えず、再利用性が下がります__。
たとえば15px余白が必要な場所で使えなくなるため、無理やり打ち消すスタイルが当てられたり、コピペされて15pxに変更されたものを見たことがある方、いるのではないでしょうか？

### 解決法

その部品がどのように配置されるかは必ず、__部品側ではなく利用側__で定義を行うようにしましょう。

```scss
  /** 利用側の定義 **/
  .form {
    display: flex;
    flex-direction: column;
    padding-left: 10px; // 10px空けたいのは利用側の都合で、部品は関知してはいけない
  }

  /** 部品側の定義 */
  .checkbox {
    // 部品には自身のデザイン情報だけをもたせる
    display: flex;
    align-items: center;
  }
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/281108/38c68df7-ee97-02af-7d12-3d4ce6808e1e.png)

`margin`や`padding`など、配置に関するスタイルを使う場合、__どこに配置を定義する責務があるか__を考えると再利用性を上げることが出来ます。
基本的なことですが、油断してるとうっかりやってしまい、コピペコードが生まれる原因を作ることになります…お気をつけください。


同様に、縦並びの余白用`margin`も

```scss
  /** 利用側 **/
  .form {
    display: flex;
    flex-direction: column;
    padding: 10px;
  }

  /** 部品側 **/
  .checkbox {
    display: flex;
    align-items: center;
  }

  .checkbox:nth-of-type(n + 2) { // 部品側で、上に他の要素があったら余白を開けるようにしている
    margin-top: 10px;
    display: flex;
    align-items: center;
  }
```
より、

```scss
  /** 利用側 **/
  .form {
    display: flex;
    flex-direction: column;
    padding: 10px;
  }

  .form > :nth-child(n + 2) { // 縦に複数並べるのは利用側の都合なので、利用側のスタイルとして定義する
    margin-top: 10px;
  }

  /** 部品側 **/
  .checkbox {
    display: flex;
    align-items: center;
  }
```

と書いたほうが、

1. 配置するコンポーネント毎にマージンを設定する必要がない
2. 利用箇所によって余白量を柔軟に変えられたり、デザインを変更したとき不必要に他の箇所に波及しない

などのメリットがあるためオススメです。


## ポイント2: サイズが固定値なのか相対値なのか意識する

`width`や`height`などでサイズを指定する際、__その要素自体のサイズを固定すべき__か、__親のサイズに従って可変すべきか__を何となくで指定するとズレる原因になります。

少々極端な例ですが、実際に見かけたことある状態を再現したものです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/281108/33ac2009-0ff3-022e-cdb1-faa26852d36d.png)

```html
  <div class="menubar">
    <i class="fas fa-bars menu_icon"></i>
    <span class="title">じゅげむ　じゅげむ</span>
    <i class="fas fa-cog config_icon"></i>
  </div>
```

一見した所、特におかしな点はありません。
ただし、CSSの指定に問題がありました。

```scss
  .menubar {
    padding: 10px;
    background-color: #566B2D;
    color: white;
    width: 100%;
    display: flex;
    align-items: center;
  }

  .menu_icon,
  .config_icon {
    width: 5%; // 確認した環境で上手く表示されることしか考えていない
  }

  .title {
    width: 90%;
    text-align: center;
  }
```

スマホサイズでは__たまたま__上手い具合に表示されますが、タブレットやPCなどで見ると描画がおかしくなります。
（逆に想定画面幅で__たまたま__上手い具合に見える固定値が指定されている時もあります）

レスポンシブを取り扱う場合、こちらのほうがポイント1よりも直接の原因になります。
PCで見た時に画面の右側が変なふうに途切れていたり、スマホで見た時変な風にはみ出ていたりというのは、大抵の場合__どこかで固定値/相対値の想定がおかしい__のが原因です。
上の例は比較的わかりやすい値ですが、`width:126%`のような全く分からない値、見たことがある方もいるのではないでしょうか？

### 解決法

サイズをとるとき、どこが固定であるべきで、どこが可変であるべきかきちんと検討する必要があります。
上記のメニューの例で行けば、

1. 固定→メニューアイコン、設定アイコン
2. 可変→タイトル部分

となるのが一般的だと思います。

```scss
  .menu_icon,
  .config_icon {
    width: 16px; // ここのアイコン幅は可変である必要がないので、きちんと指定する
    flex-shrink: 0; // タイトル部分をgrow指定する場合、潰れないようにshrinkも一応指定する
  }

  .title {
    width: calc(100% - 32px); // アイコン2つ分のサイズを引く
    // または
    flex-grow: 1; // タイトル部分を伸ばすよう指定する

    text-align: center;
  }
```

どこが固定でどこを相対にするか、また相対にする場合は正確なサイズ計算を指定するように意識すれば、どのデバイスで見ても表示崩れは起こりにくくなると思います。

## まとめ

個人的なポイントを2点まとめました。
例としては__間違っている点が分かりやすい__ものを選んだため、「こんなことやらないよ」と思われてしまうかもしれません。
ただ、手癖で書くと細かいところで混入してしまい、塵も積もって…となりがちなことですので、書いたあとに思い返していただけたら幸いです。