テクノロジー

2020.09.08

表示速度を飛躍的に向上させるHTML/CSS最新仕様「content-visibility」「Lazy loading」「contain」をコード付き簡単解説

表示速度最適化の仕様、content-visibility,Lazy loading,contain

こんにちは、お久しぶりです。岡部和昌(@kzms2)と申します。

突然ですが、弊社ヤフーがW3Cという標準化団体に参加しているのはご存じでしょうか。

W3C(ダブリュースリーシー)とは、各種ウェブ関連技術の標準化を推進する非営利の標準化団体の名称です。正式名はWorld Wide Web Consortiumで、ティム・バーナーズ=リーによって1994年に設立されました。また現在は400を超える会員組織を擁しており、主要な規格はHTML、XML、MathML、DOMなどがあります。

ヤフーは2018年10月から、ウェブの各種技術の標準化を推進するW3Cに参加しています。

自分はその活動に関して積極的に取り組んでおり、今回はその活動下で得た表示速度改善系の情報で有益だと感じたものをいくつかコード付きで簡単に解説します。

随分と前から存在している仕様の説明もありますが、表示速度向上に関しての最新のナレッジも含めた内容をシェアできればと考えています。

まずはじめに

今回紹介する仕様などは以下の通りです。全て知っていたらそっとこの記事を閉じてください。

  1. loading属性(Lazy loading)
  2. content-visibilityプロパティ
  3. containプロパティ

content-visibilityプロパティが今回のイチオシなのですが、説明する順番的にまずはLazy loadingに触れたほうが理解しやすいので、その順番で説明していきます。また今回は要素の読み込みや表示を調整するモノに的を絞って説明していきます。

1. Lazy loadingを可能にするloading属性

Lazy loadingとは画像がビューポート外にある時は読み込みを実行せず、ビューポートに近づいた時に画像の読み込みを開始する、表示速度を最適化する名称のことです。

説明
auto 既定値。画像の読み込み方をブラウザの実装に委ねる
lazy Lazy loadingを有効にする
eager 画像をビューポート外でもすぐに読み込む(全ブラウザの基本動作)

これまではJavaScriptを用いて実装するしかありませんでしたが、ついにimgiframe要素であればloading="lazy"を付与するだけで、簡単に実装できます。

<!-- 画像に適用する場合 -->
<img src="pic.png" alt="画像の詳細" loading="lazy">

<!-- iframeに適用する場合 -->
<iframe src="external.html" loading="lazy"></iframe>

画面外では読み込みが発生しないので、必要になった時(画面内に要素が入りそうになった時)に読み込みが発生するのでパフォーマンスが向上します。

loading属性がeagerの場合は画面外でも読み込まれるが、loading属性がlazyの場合は画面外では読み込まない

また画像についてはsrcsetを用いたレスポンシブな画像に対しても指定できますし、picture要素を用いてfallback形式でも記述できます。

<img src="normal.png"
  srcset="large.png 1024w, medium.png 640w, small.png 320w"
  sizes="(min-width: 36em) 33.3vw, 100vw"
  alt="画像の詳細" loading="lazy">

<picture>
  <source media="(min-width: 1024px)" srcset="large-image.png 1x, large-image@2x.png 2x">
  <source srcset="image.png 1x, image@2x.png 2x, image@3x.png 3x">
  <img src="fallback.png" loading="lazy">
</picture>

※読み込みの初期段階で表示させたい要素、例えばファーストビューのメイン画像などには付与しないのが望ましいです。

対応ブラウザ

Edge,Firefox,Chrome,Android Chrome,Android Browserが対応ブラウザです

※対応ブラウザの表はIEはバージョン11で、その他は最新バージョンの対応状況です(2020年9月8日現在)

その他

ちなみにFacebookのソーシャルプラグインもLazy loading対応しているのですが、こちらはdata-lazy="true"と書き方が異なるので注意が必要です。(公式のページプラグイン - ソーシャルプラグイン(外部リンク)を参照ください)

<div
  class="fb-like"
  data-href="https://www.yahoo.co.jp/"
  data-lazy="true"></div>

※この書き方はW3Cの定義とは関係がないので、仕様というよりはFacebookのソーシャルプラグインだけに対する書き方だと思ってください

2. content-visibilityプロパティ

2020年8月末リリースのChrome85に実装された機能で、本日記載している内容で一番新しい仕様です。

このプロパティが優れもので、指定した要素の描画をスキップして、ビューポートに近づくと描画 を行います。Lazy loadingデータの読み込みを遅延実行し、一方で、content-visibility表示(レンダリング)を遅延実行します。

説明
visible 既定値。要素の内容は、状態にかかわらずレイアウト・描画される
hidden 要素の内容のレイアウト・描画をスキップする(display:none;と近い挙動)
auto 要素のレイアウト・スタイル・塗りの封じ込めをオンにする。要素はクライアントが表示を求めない状態の時にはスキップする(ビューポート外など)

content-visibility: auto;とその要素を描画する予定の高さの指定をcontain-intrinsic-sizeのプロパティを用いることによって使用できます。

<style>
section {
  content-visibility: auto;
  contain-intrinsic-size: 500px;
}
</style>
<main>
  <section>…セクションの中身いろいろ</section>
  <section>…別の内容のセクションの中身いろいろ</section>
  <section>…そのまた別の内容のセクションの中身いろいろ</section>
</main>

上記の指定だと、各sectionがビューポート外にある時は、高さを500pxを保持して中身がない状態で、描画がスキップされます。それにより無駄な描画をしないで済むので、読み込み速度が劇的に速くなります。

content-visibilityがvisibleの時は、要素が画面外でも描画されるが、content-visibilityがautoでcontain-intrinsic-sizeの値が500pxなどと指定してある場合は画面外では描画されない

ただしcontain-intrinsic-sizeの値を適切に設定しないと、指定したsectionがビューポート内に近づいた時に要素の高さが変動してしまいます。概算でも良いのである程度「その要素が本来保持するであろう高さ」を設定してください。

対応ブラウザ

Chromeのみが対応ブラウザです

3. containプロパティ

「レイアウト・スタイル・塗りの封じ込め」という表現が上記content-visibilityauto値の説明で出てきましたが、このcontainプロパティの振る舞いが参考になるかもしれません。

content-visibility: auto;を要素に指定した場合、ビューポート外にある時はcontain: style layout size;が適用された状態に近いと考えてよいです。

ちなみにこのcontainプロパティ、Chrome52という随分前の段階ですでに実装されているので厳密に言うと最新の仕様ではありませんが、content-visibilityの影響もあってか最近仕様のアップデートが行われています。

説明
none 既定値。封じ込めは行わない
strict contain: size layout paint;と同等
content contain: layout paint;と同等
size 指定した要素のサイズを封じ込め、子孫の影響をけないことを保証する。指定した時にはwidth, heightの指定をしないと要素の縦横幅がない状態で扱われることに注意
layout 指定した要素のレイアウトを封じ込め、親兄弟要素の影響を受けないことを保証する
paint 指定した要素の外側に、子孫要素が描画されないことを保証する
style 指定した要素とその子孫以外に、影響を与える可能性のあるプロパティについて封じ込めることを保証する。この値は仕様書で「リスクあり」と明示されているので注意が必要
<style>
.timeline-item {
  contain: strict;
}
</style>
<ul class="timeline">
  <li class="timeline-item">style以外を封じ込めても問題ない要素</li>
  <li class="timeline-item">style以外を封じ込めても問題ない要素</li>
  <li class="timeline-item">style以外を封じ込めても問題ない要素</li>
</ul>

指定する値や条件にもよりますが大まかには以下のような状態です。

初期描画されたのちに要素を追加・一部書き換えした時、containがnoneの場合は全体が再描画され、containがstrictなどの場合は閉じ込めた条件で再描画される

基本的にCSSの描画は一部が変更されただけでも全体の再レンダリングが必要となるのですが、このcontainプロパティを用いることで指定した箇所のCSSのツリーの指定した描画などを封じ込めて、その中でのレンダリングは全体に影響を及ぼさないようになります。

これだけ聞くと良い点しかないように感じられますが、レンダリングを封じ込めるということはその指定した要素の変更が全体のレンダリングに影響しなくなるということなので、例えば非同期で子要素が更新された時、閉じ込めた中身が想定よりもコンテンツが多かった場合は表示されず、表示崩れを起こしてしまいます。

おそらくは上記の「値の説明」を読んでも正直意味がわからない方が多数だと思うのですが、「その要素自身に対して指定した値は、親や兄弟とは別軸でレンダリングされる」と考えると良いかもしれません。

これらの挙動や振る舞いに関しての詳細は、ブラウザの描画に関しての知識が必要なので、「ブラウザ レンダリング」でヤフって見てください。

またの機会にここも掘り下げて書いてみたいと思っています。

対応ブラウザ

Edge,Firefox,Chrome,Android Chrome,Android Browserが対応ブラウザです

まとめ

  1. Lazy loadingをimgiframeに実装したい!
    • loading="lazy"を該当要素に追加
  2. 画面外で要素の描画をスキップして表示を速くしたい!
    • content-visibility: auto;contain-intrinsic-size: 500px;を該当要素に指定(500のところは適宜書き換え)
  3. 描画領域が決まっている箇所、また非同期通信などで取得する要素の描画を速くしたい!
    • サイズが変化しない場合はcontain: strict;を、サイズが可変の場合にはcontain: content;を該当要素に指定(必要に応じて値は変更)

このどれもすべての要素に指定するなどの暴挙は行わず、必要と感じた箇所にのみ指定をしてください。優先的に読み込みたい・表示させたい要素には指定しないことをオススメします。

また新しく追加された仕様ということもあって、仕様自体に変更が入る可能性が十分にありえます。W3CやWHATWGなどの一次ソースの確認を定期的に行い、仕様に変化が出ていないかなどの確認を行ってください。

情報を追う自信がない方は、岡部のTwitter(@kzms2)をフォローしておいていただければこれらの情報は必ずつぶやきます。

最後に一言と注意点

いかがでしたか。対応ブラウザに偏りがあるものの、比較的簡単に実装できることがわかったかと思います。注意点を強いて挙げるならば、まだ実装されたばかりなので、バグがある可能性、仕様が変更される可能性がある という点でしょうか。実際にcontain: style;に関しては最近でも仕様の扱い方が揺れ動いています。

UIやデザインには好みがあるけど、ページが速く表示されて文句言う人はいない です。

今回はこれらの内容について 「簡易的に理解をしたい」 という方向けに書きました。仕様や詳細に関しては最後に参考リンクを貼っておくので、原文を見に行って読むことをとてもオススメします。

参考リンク(外部リンク)


岡部 和昌(@kzms2)

第4〜6代目 HTML5黒帯

第4〜6代 HTML5/ウェブデベロップメント黒帯として活動、Yahoo! JAPANトップページのコーディング業務を長く担当、2008年のリニューアルにも関与した。最近はフロント系技術の動向を追いつつ、W3C活動に注力している。またHCI関連にも興味があり、海外トップカンファレンスのUISTやMobileHCIにてUI系の論文も採択された。

Yahoo! JAPANでは情報技術を駆使して人々や社会の課題を一緒に解決していける方を募集しています。詳しくは採用情報をご覧ください。

関連記事

このページの先頭へ