＜CSS＞サイトの表示速度を意識したセレクタの書き方

## 画面の表示速度を意識してCSSを書こう
WEBページの表示速度を高速に保つことでサイトの直帰率を防げたりSEO上の観点でも有利に働くことはよく知られている事実かと思います。
2018年2月に更新されたGoogleのダニエル・アンによる研究結果ではスマホページにおいてloadingタイムが1秒から5秒に増えると直帰率は90%増加するそうです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/225425/43c84131-5c5e-464c-7dc6-806c90a7868c.png" width="450">
>  [think with Google](https://www.thinkwithgoogle.com/marketing-resources/data-measurement/mobile-page-speed-new-industry-benchmarks/)


表示速度を早める方法はサーバーサイド側での改善など多くの手法がありますが、CSSセレクタを最適化することでWebページの表示速度に貢献できることを知っていますか？
『CSSセレクタの最適化』といった観点でサイトの読み込み速度を上げる方法をご紹介します。

### CSSセレクタの照合は左から右？
```css

#main-visual > .main-visual__title {
  font-weight: bold;
}
```
ブラウザがこのコードを左から右へ順にマッチしていくと考えると、このルールはそれほどコストがかからないと思えます。
1. ページに一つしかない `main-visual` 要素を見つける
2. その子の `main-visual__title` を見つける
3. スタイルを適用


### 正解は...
```css

#main-visual > .main-visual__title {
  font-weight: bold;
}
```
実際には<font color="DeepPink">CSSセレクタは右から左へ照合</font>されます。
1.  `main-visual__title` を探す
2. その親要素が `main-visual` かどうかを調べる
3. スタイルを適用

`main-visual` はページに1箇所しかないのがわかっているのに最初に検索するのは`main-visual__title`。
とても効率が悪いですね。レンダリング速度が低下してしまいます。
ちなみに一番右端のセレクタは<font color="DeepPink">キーセレクタ</font>と呼ばれています。
このことから、キーセレクタに適用範囲が大きいセレクタを指定してしまうと照合するのに時間がかかりそうです。

### シンプルに定義しよう
```css

.main-visual__title {
  font-weight: bold;
}
```
ベストプラクティスは対象となるセレクタだけを指定することです。
そうすることによって無駄な検索が行われないので、レンダリング速度の低下を抑えられます。

## CSSの書き方NG集
### NG①：要素セレクタを組み合わせて使う

```scss

ul.menu {
  padding-right: 5px;
}
```
要素セレクタが変更になったときのメンテナンスが面倒にもなります。
クラスセレクタだけで十分です。

```scss

.menu {
  padding-right: 5px;
}
```
### NG②：複雑な子孫セレクタ

```scss

.c-table {
  &.c-table--form {
    tbody {
      tr {
        th {
          border-top: 1px solid #ffffff;
        }
      }
    }
  }
}  

```

ネストが深いぶん照合に時間がかかります。
もっとシンプルにしましょう。


```scss

.c-table {
  &.c-table--form {
    th {
      border-top: 1px solid #ffffff;
    }
  }
} 

```
※要素セレクタの`th`ではなくクラスセレクタでも可。

また、modifireの`c-table--form`が`c-table`のあとに記述されるルールであるならばもっとシンプルに記載できます。

```scss

.c-table--form {
  th {
    border-top: 1px solid #ffffff;
  }
} 

```

> <font color="#CD0">Bad CSS</font>：Redundant tags selectors（参照）

### NG③：ulとliの併用

```scss

.menu-wrap {
  ul {
    li {
      border-bottom: 1px solid #cccccc;
    }
  }
}
```

`<li>`セレクタはほぼ常に`<ul>`タグに内包されているので`<ul>`の指定を外しましょう。

```scss

.menu-wrap {
  li {
    border-bottom: 1px solid #cccccc;
  }
}
```

> <font color="#CD0">Bad CSS</font>：Redundant tags selectors（参照）

## NG集はわかったけど、それって本当に遅くなるの？
[『続・ハイパフォーマンスWebサイト』](https://www.oreilly.co.jp/books/9784873114460/)に掲載されている[サイト](http://stevesouders.com/efws/css-selectors/baseline.php)を活用し実際に計測してみました。
基準となるHTMLが用意されており、ページごとにCSSのセレクタの指定方法が異なります。それぞれのページにアクセスした際、表示速度がどれくらいになるのかをページ内のpage load time欄に表示してくれます。
Chrome,Firefox,IEで実際にアクセスし、page load timeの数値を記録して表にしました。

### 測定基準となるHTML

```html

<div>
  <div>
    <div> <p> <a id='id0001' class='class0001'>0001</a> </p> </div>
    ...
    <div> <p> <a id='id1000' class='class1000'>1000</a> </p> </div>
  </div>
</div> 
```

### 対象CSS

```css
// 未適用
.noclass0001 { background: #CFD; }
...
.noclass1000 { background: #CFD; }


// 要素セレクタ
A { background: #CFD; }
.noclass0001 { background: #CFD; }
...
.noclass1000 { background: #CFD; }

// クラスセレクタ
.class0001 { background: #CFD; }
...
.class1000 { background: #CFD; }

// 子セレクタ
DIV > DIV > DIV > P > A.class0001 { background: #CFD; }
...
DIV > DIV > DIV > P > A.class1000 { background: #CFD; }

// 子孫セレクタ
DIV DIV DIV P A.class0001 { background: #CFD; }
...
DIV DIV DIV P A.class1000 { background: #CFD; }

// ユニバーサルセレクタ
P.pclass0001 * { background: #CFD; }
...
P.pclass1000 * { background: #CFD; }

// 遅めのセレクタ
#id007 > A { ... }

```

|        |       Chrome |    Firefox    | IE11       |
|:-------|:---------:|:------------------:|:--------:|
| 未適用（Baseline）|   12|        26|14|
| 要素セレクタ（Tag）|  45|       30|28|
| クラスセレクタ（Class）|  44|        28|28|
| 子セレクタ（Child） | <font color="Red">102</font>|         <font color="Red">100</font>|<font color="Red">279</font>|
| 子孫セレクタ（Descendant） |  47|       33|13|
| ユニバーサルセレクタ（Universal）|   51| 29|<font color="Red">248</font>|
| 遅めのセレクタ|   <font color="Red">131</font>|<font color="Red">98</font> |<font color="Red">121</font> |

http://stevesouders.com/efws/css-selectors/baseline.php


> ※ChromeはMac Sierra、FirefoxとIE11はWindows7
※キャッシュ削除し単一タブで検証（2018.3.1現在）




ブラウザによって表示速度の大小はあるものの、セレクタの書き方による変化は見て取れました。
ここから判明したことは

- 子セレクタが圧倒的に遅い
- クラスセレクタが一番早い？
- キーセレクタで要素セレクタを指定（上記の遅めのセレクタ）の場合複合セレクタの数に関係なく遅くなる

ということです。
ただこの検証結果の数値は回線速度などの環境による影響を受けやすいので、あくまでも一例として捉えていただければと思います。

# その他の表示速度を上げる方法
いままではCSSをどのように書くと表示速度が遅くなるのかを調査しました。
それ以外にもやるべきこととしてCSSファイルサイズを小さくする方法があります。

## CSSファイルのサイズを抑えてレンダリング速度をあげよう
CSSファイルのサイズが大きくなると読み込みに時間がかかる原因となり、表示速度に影響を与えてしまいます。
コーダーはファイルサイズをなるべく小さくすることを念頭に置きながら開発する必要があります。
無駄な記述を少なくすることでファイルサイズを小さくし、レンダリング速度に貢献しましょう。

### サイトを多角的に分析！
サイトのJSやCSSについて細かく分析してくれる[Yellow Lab Tools](http://yellowlab.tools/)があります。GithubのStarが1403あるので多くに支持されているサービスのようです。
こちらのサイトを使って自分の担当サービスの改善点を洗い出してみました！
サービス名を公表できない関係上、ソースコードを一部改変しています。
以下、指摘事項のなかでも特に気になったCSS関連の指摘をピックアップして改善案を提示していきます。

#### 指摘①：複合セレクタを3つ以内にしよう
`#header ul li .foo` のように4つ以上のセレクタは表示速度低下を招きます。複合セレクタは3つ以内になるように心がけましょう。
該当箇所が409ありました。
9セレクタを指定しているところもありました:disappointed_relieved:

指摘例：

```scss

.hogehoge .hugahuga .eeee .mada span.konnani {}
.selector .shiteishiteru:hover .ooina>a .waaaaaaa {}
```


> <font color="#F60">CSS complexity</font>：Complex selectors（参照）


#### 指摘②：古いベンダープレフィックスを削除しよう
ブラウザのバージョンが常日頃アップされているのに伴い、使われなくなったベンダープレフィックスが残っていました。

- `-moz-box-sizing: content-box`
   - Firefox28以前
- `-webkit-border-radius: 16px`
   - Androidブラウザ2.1、Chrome4、iOS Safari3.2 Safari4以前
- `-ms-transform-origin: 0 0`
   - IE9以前

特に読み込まれている`colorbox.css` で多々指摘されており、それは2016年7月からアップデートされていないようです。

> <font color="#CD0">Bad CSS</font>：Old prefixes（参照）

#### 指摘③：ルールの２重記述を見直そう
CSSのルールが２重に記載されている箇所が31箇所ありました。
うまくマージをする必要があります。

例：

```scss:xxxxxx_top.scss/L985
.hoge .huga {
  float: left;
  margin: 0;
  width: 70px;
  text-align: center;
}
```

```scss:xxxxxx_top.scss/L1026

.hoge .huga {
  position: relative;
  float: left;
  margin: 0;
  padding-right: 10px;
  width: 50px;
  text-align: center;
}
```

> <font color="#CD0">Bad CSS</font>：Duplicated selectors（参照）

#### 指摘④：似通ったカラー定義を見直そう
似たようなカラーが散見されるという指摘内容です。
確かにほぼ一緒のカラーがある。。。
主要カラーは変数で定義し管理しているはずだけれども、それ以外で使っているカラーが多く指摘されているようです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/225425/afc6a630-5479-8aad-2b47-cd6a18b1052e.png)

><font color="#F60">CSS complexity</font>：Similar colors（参照）

#### 指摘⑤：CSSのルールが膨大すぎるので見直そう


|        |  CSS      |      Rule |
|:---------:|:-------|:---------:|
|1| application.css|   2806|
|2| xxxxxx_common.css|  1677|
|3| jquery-ui-1.10.3.custom.min.css|  357|
|4|xxxxxx_top.css|  307|
|5|jquery.mCustomScrollbar-3.1.5.css|254|
|6|xxxxxx_calendar.css|  119|
|7|colorbox.css|   24|
|合計||   5544|

該当のページでは5544のルールが使われているという結果がでました。圧倒的に多い...

ルールを減らすのを目的とするというよりかは、今までの指摘①～④を修正することによって結果としてファイルサイズが減少するといったところでしょうか。

ルールは750以下にするとスコア100を取れるようです。
コンポーネントをまとめている`application.css` だけで2806もルールがあるので、750まで抑えるのはなかなか難しいです。ただ357ルールが定義されている `jquery-ui-1.10.3.custom.min.css` や254ルールある`jquery.mCustomScrollbar-3.1.5.css` などプラグインとして必要なCSSも膨大なルールが定義されているので、必要なスタイル定義だけを自サイトで管理するようにして不必要なルールを書き込まないような運用も検討したいです。

> <font color="#F60">CSS complexity</font>：Rules count（参照）

## まとめ
CSSは簡単にかけて自由度が高いですが、セレクタの指定の仕方一つとっても表示速度に影響するとなると、注意が必要です。特に複数人で開発を行うようなサービスにおいては共通認識がないと表示速度が遅くなるようなCSSが散見されてしまいます。
サイトの表示速度はユーザー離れの要因の一つにもなりかねないので、UX体験を向上させる一つとしてCSSの書き方には注意を払っていきたいですね。


## 参考
- [GitHubがCSSのパフォーマンス改善のためにおこなったことをまとめたスライド - coliss] (http://coliss.com/articles/build-websites/operation/css/slide-githubs-css-performance-by-jonrohan.html)
- [続・ハイパフォーマンスWebサイト - ウェブ高速化のベストプラクティス - O'Reilly Japan](https://www.oreilly.co.jp/books/9784873114460/)
- [Find out how you stack up to new industry benchmarks for mobile page speed - think with Google] (https://www.thinkwithgoogle.com/marketing-resources/data-measurement/mobile-page-speed-new-industry-benchmarks/)