CSSについて誰も私に教えてくれなかった大切なこと -プロパティやセレクタがパフォーマンスに与える影響
Post on:2019年4月11日
当ブログでもCSSのさまざまなテクニックについて記事にしていますが、今回は表面的なものではなく、CSSの本質的なパフォーマンスに関することを紹介します。
パフォーマンスを意識すると、実装も変わってくると思います。
Things nobody ever taught me about CSS.
by Charlie Gerard
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
この記事は私がこれまで一緒に働いたことのある人を批判するものではありません。個人的にCSSについて調べて、学んだことのリストです。
多くのデベロッパーがCSSについてあまり気にかけていないという事実は目新しいことではありません。ネット上や、友人・同僚と話すことでそのことに気がつきます。しかし、コミュニティでは学ぶことの多くが仲間との知識共有から生まれています。その結果、私は今まで一度も言われたことのないCSSについての本質的なことがあることを認識しました。
私は個人的に調べ、CSSをよりよく理解して書くために私が興味深く有用であると思うコンセプトのリストをまとめることにしました。このリストは完全に網羅されているわけではありません。私が学んだこと、そして他の人に役立つことができる場合に備えて共有したいことが含まれています。
CSSの用語
CSSにはすべてのプログラミング言語と同様に、コンセプトを説明するために使用される用語があります。CSSも他の言語と同じです。用語を習得することは、コミュニケーションの手助けや自分の知識のためにも重要です。
子孫結合子(descendant combinator)
例えば、セレクタの間にある空白スペースが何と呼ばれるか知っていますか?
これは子孫結合子と呼ばれるものです。
1 2 3 4 5 |
/* uiとliの間の空白スペースは子孫結合子と呼ばれます。 */ ul li{ background-color: pink; } |
レイアウト、ペイント、コンポジット
これらの用語はブラウザがどのようにレンダリングするかに関係していますが、レンダリングのさまざまなステップに影響を与えるCSSのプロパティがあるため、重要です。
1. レイアウト(Layout)
レイアウトは、要素がスクリーン上に存在するときにどのくらいのスペースが必要かを計算します。CSSのレイアウトプロパティ(width, heightなど)を変更すると、ブラウザは他のすべての要素を確認してページをリフローする必要があります。つまり、影響を受けるエリアを再描画してそれらを合成します。
2. ペイント(Paint)
ペイントは、要素のすべての視覚的部分(color, borderなど)のピクセルを塗りつぶす処理をします。要素を描画することは通常、レイヤー上で行われます。
CSSのペイントプロパティは変更してもページのレイアウトには影響しないので、ブラウザはレイアウトのステップをスキップしますが、それでもペイントは行われます。
ペイントはこれらの中で最も負荷がかかります。
3. コンポジット(Composite)
コンポジットは、ブラウザが正しい順序でレイヤを描画する必要があるステップです。一部の要素は互いに重なり合う可能性があるため、このステップは要素が意図した順序で表示されるようにするために重要です。
もしレイアウトもペイントも必要としないCSSのプロパティを変更した場合、ブラウザはコンポジットを行うだけで済みます。
CSSのどのプロパティがレイアウト・ペイント・コンポジットに影響を与えるかについては、CSS Triggersに一覧があります。
CSSのパフォーマンス
子孫セレクタは高負荷になる可能性がある
アプリケーションの大きさにもよりますが、子孫セレクタを特定的な指定なしで使用すると、非常にコストがかかる場合があります。その関係は親子に限定されないため、ブラウザはすべての子孫要素の一致を確認するからです。
1 |
#nav a{ } |
ブラウザは#nav内を解析する前にページ上のすべてのリンクを解析します。
パフォーマンスをよくするためには、#nav要素内の各<a>を特定できるセレクタ(.navigation-linkなど)を追加します。
ブラウザはセレクタを右から左に読む
この知識は必須ですが、私は知りませんでした。
ブラウザはCSSを解析するとき、CSSのセレクタを右から左に解決します。下記のコードを見てみてください。
1 2 3 |
.container ul li a{ color: green; } |
実行される手順は下記の通りです。
- 最初に、ページ上のすべての<a>を解析します。
- <li>に含まれるすべての<a>を見つけます。
- 上2つで一致した要素の中から、<ul>に含まれるものを見つけます。
- 最後に、.containerを持つ要素に含まれるものに絞り込みます。
この手順を見ると、右にあるセレクタがより特定的であるほど、ブラウザはCSSのプロパティを見つけるときに効率的になることが分かります。
上記の例のパフォーマンスを向上させるには、.container ul li aの代わりに<a>タグ自体に.container-link-styleのような特定できるセレクタを追加します。
レイアウトを可能な限り変更しない
一部のプロパティを変更すると、レイアウト全体をアップデートする必要があります。
例えば、width, height, top, leftのようなプロパティを変更すると、レイアウトは計算されることを必要とし、レンダーツリーをアップデートする必要があります。
多くの要素でこれらのプロパティを変更すると、それらの位置やサイズを計算して更新するのに長い時間がかかります。
ペイントの複雑さに注意
ペイントに関しては、CSSプロパティの中には他のものよりも高負荷なもの(blurなど)があります。同じ結果を得るために、他のより効果的な方法がないか検討してください。
高負荷なCSSのプロパティ
いくつかのプロパティは他よりも高負荷です。これが意味するのは、描画するのにより長い時間がかかるということです。
特に負荷が高いのは下記のプロパティです。
- border-radius
- box-shadow
- filter
- :nth-child
- position: fixed
これらをまったく使用してはいけない、という意味ではありません。しかし、これらを使用して何百回もレンダリングすると、レンダリングのパフォーマンスに影響を与えることを理解しておく必要があります。
CSSの記述の順番
CSSファイルの順番が重要
下記のコードを見てみてください。
1 2 |
.red{color: red;} .blue{color: blue;} |
そしてこのスタイルを適用するHTMLです。
1 2 |
<div class="blue red">This is will be blue</div> <div class="red blue">This is will be blue</div> |
HTMLのセレクタの順番は関係ありませんが、CSSファイルでの順番は関係があります。
CSSのパフォーマンスを確認する良い方法は、デベロッパーツールを使用することです。
ChromeまたはFirefoxを使用している場合は、デベロッパーツールを開いて「パフォーマンス」タブに移動し、ページを読み込んだり操作したりした時に何が起こっているのかを記録できます。
デベロッパーツールの「パフォーマンス」タブ
リソース
この記事を書くために調べている間、私はいくつかの便利なツールに出会いました。
- CSS Triggers: CSSのプロパティを変更したことによるパフォーマンスへの影響をまとめたリスト
- Uncss: 未使用のスタイルをCSSから削除するためのツール。
- CSS-explain: CSSのセレクタを説明するツール。
- Fastdom: レイアウトのパフォーマンスを向上させるためにDOMの読み書き操作をバッチ処理するためのツール。
この知識があなたの役に立つことを願っています。
ここまで読んでくれて、ありがとうございます。
sponsors