IE亡き後のマークアップを調べてみる
この記事は食べログアドベントカレンダー2020の4日目の記事です。
この記事を執筆するのは、食べログでフロントエンドチームに所属する佐伯です。
皆さんマークアップはお好きでしょうか。僕は好きです。
HTML、CSSでWebサイトが作れるのはもちろんのこと、CSSやSVGを駆使すれば、JavaScriptが必要になりそうであろう複雑なUIなども簡潔に作成出来るからです。
JavaScriptはBabelなどのおかげでIE11も比較的対応しやすいですが、マークアップはそうはいきません。Polyfillが対応していないことや、対応していたとしてもReactなどのフレームワークとの共存出来るかなど問題点があるため、IE11に合わせるしかありませんでした。
しかしながら、IE11の情勢も変わってきました。
2020年3月よりIEでYoutubeを閲覧するとアラートが表示されるようになっています。
またedge87よりIE非推奨ページをIEで開くとedgeに自動的にリダイレクトされる機能が追加され、サポート終了を待たずともIEのシェアは今後更に減っていくことでしょう。
もちろんサービスに応じてIE対応が必要となることもありますが、IE対応しないサービスも増えてきますのでモダンなブラウザで実現出来る表現を学び直してみたいと思います。
※この記事では(Chrome, Edge, Firefox, Safari)をモダンブラウザと呼んでいます。
CSSによるSVG Animation
HTMLの要素をアニメーションさせる際は cssのtransitionやanimationを使うと思います。しかしながらIE11ではSVGの要素に対してCSSアニメーションを適応出来ませんでした。
なのでIE11対応するためにJavaScriptを書く必要がありましたがモダンブラウザでは簡単に作成できます。せっかくなのでstroke-dashoffsetやfillを動かしたanimationを用意してみましょう。
こちらはSVGを用意するだけで、lineアニメーションや, 塗りつぶしのアニメーションのスタイルを自動生成してくれるWebツールです。
https://svgartista.net/
JavaScriptを使わずにアニメーション出来るなんてとても簡潔で気持ちいいですよね。アニメーションの発火だけをJavaScriptで行い、動作はCSSに任せています。
SVG SMIL animation
引き続きSVGを見ていきます。モダンブラウザであればSVG内でアニメーションが出来るようになるのですが、一つ対応出来ないアニメーションがあります。パスに沿ったアニメーションです。
モダンブラウザはSMIL animationという仕様を使うことでパスに沿ったアニメーションを作ることが出来ます。
SVGのタグの中にanimationを定義したタグを入れるような形で実装され、アニメーションの実行、停止はJavaScriptで動かすことも出来ます。
IE11に対応する場合はSVGの"SVGPathElement.getPointAtLength()"というAPIを用いて、フレーム毎に座標を取得し要素を動かなければいけないので一手間が必要になります。
便利なSMIL animationですが懸念事項もあります。以前chromiumでSMIL animationをdeprecateにしましょうという提案がありました。
しかしながらその提案は代わりになるような仕様が整っていないために一旦は取り下げられています。
長期的に続くプロジェクトでは採用しづらいですが、LPなど短期でリッチな見た目を要求するようなページで使うと良さそうですね。
CSS Motion Path
SMIL animationの代わりなるものの一つとしてCSS Motion Pathという仕様があります。Safariはまだ未対応の仕様です。
これが使えるとどうなるかといいますと、CSSにPathが埋め込めます。
そして埋め込んだPathに沿ってCSSだけでアニメーションが出来ます。
これは実物をみた方が早いので以下がサンプルです。
先ほどの例からSMIL animationの記述がなくなり、CSSにPathが直接書かれています。
"offset-path: path()"と"offset-distance: n%;"でアニメーションが出来てますね。CSSなので@keyflamesで管理できますし、classの付け替えでon / offを切り替えられます。
とても素晴らしい仕様なのですが問題点がありまして、最初にも書きましたがSafariに対応していません。
また、SVGのPathを参照して使いまわしたいですがurl()の値の指定も動きません。もうしばらくは様子見ですね。残念。
Variable fonts
バリアブルフォントは幅、太さ、スタイルごとに個別のフォントファイルを用意するのではなく、書体のさまざまなバリエーションを 1 つのファイルに組み込むことができる OpenType フォント仕様の進化版です。CSS および単一の @font-face 参照を介して、特定のフォントファイルに含まれるすべてのバリエーションにアクセスできます。
引用元: バリアブルフォントガイド
太字や斜体など複数のフォントスタイル使いたい場合、その分だけフォントファイルを読み込む必要がありました。ですがバリアブルフォントを使用すると複数のフォントスタイルを一つのフォントファイルより定義することができるようになります。
例として身近でVariable fontsに触れられるGoogle Fontsを覗いてみましょう。
Google Fontsで"Show only variable fonts"のチェックを入れると使用可能なVariable fotnsを調べることが出来ます。(欧文フォントで77件ありました)
これらのfontの説明にはaxis(軸)の項目があり、Variable fontsはそれらのaxisを可変させることによって異なるweightなどを表現します。
以下はRoboto Monoの例で、"Italic"、"Weight"の2軸を操作出来るようになっております。
さて、欧文はVariable fotnsが見つかるのですが和文のVariable fotnsは2020年11月現在、出回ってなさそうです。
和文のフォントファイルサイズは元から大きいのでVariable fontsとして作るのは大変なんでしょうね。。。
というわけでいまのところ、恩恵少ないようにも思えるのですがVariable fontsを使ってアイコンフォントをアニメーションさせたりも出来ます。
こちらはAniconsというリポジトリのものです。
Variable fontsに用意した"Time"というaxisを変化させてアニメーションを行っています。このように予めアイコンフォントでインタラクションを定義しておけばtransitionでfontを可変することができます。
サービスで使うアイコンをインタラクションを含めて作れたらとても便利そうですよね。
実装についてや、Variable fontsについて詳しく知りたい方はこちらをどうぞ。このセクションはこの記事を元に作られてます。
https://web.dev/variable-fonts/
Variable fontの作り方はこちらなどが参考になります。
https://glyphsapp.com/learn/creating-a-variable-font
CSS Grid Layout
"display: grid" これはご存知の方は多いと思います。
メディアクエリと合わせればレスポンシブデザインも、最小限のHTMLで構築することが出来ます。
以下は"grid-template-areas" を用いた、レスポンシブデザインのサンプルです。
画面幅に応じて同じHTMLで1カラム、2カラムと簡単に切り替えられます。
さて、お気づきの方もいらっしゃると思いますが上記のlayoutはAutoPrifixerを使用すればIE11にも導入することが出来ます。この記事の趣旨と異なりますね。
grid layoutは現状IE11でも十分に使えますが、一部使えないプロパティがあります。"grid-template-columns"の repeat()です。
マークアップをしている人であれば、固定幅のタイルを中央寄せかつ、最終行は左詰というレイアウトに出くわした方がいらっしゃるのではないでしょうか。
IE11以前の場合、中央寄せしたflexのコンテナの中に、左詰のlistを入れるなどでは実現出来ないんですよね。
モダンブラウザではrepeatが使えるので、簡潔に書くことができます。
"repeat(auto-fit, 300px);"
これだけでIE以前で表現出来なかったlayoutが簡単に表現できるのはとても便利ですね。またカード間のmarginもgapを指定するだけで済むのでとても読みやすいです。
ちなみにIE11で同様のことをしたい場合、HTML側に小細工を入れると可能になります。
予め中身が空の要素をいれておき、その上で"displax: flex"と中央寄せを指定することで見かけ上は同じlayoutを作ることが出来ます。
残念な点としてはコンテンツに関係の無い要素を埋め込む必要があり、最大カラム数 - 1の空要素を埋め込んで置かないと画面幅を広げた際にレイアウトが崩れます。HTMLとCSSに依存関係が発生しちゃうんですよね。
またタイル間のマージンを用意するために、子要素にマージン、親要素にそれに対応するネガティブマージンをつける必要があるため、マージン修正する際に二箇所直す必要も出てきてしまうため出来れば避けたいスタイルです。
CSS Filter Effects
今度はモダンブラウザ全てで動くFilter Effect です。
IE対応でぼかし表現するとなるとSVGでfilter用意するなど、手間がかかりますがモダンブラウザはプロパティを指定するだけで出来ちゃいます。
簡単すぎて言うことないですね。
transitionも効きますし、filterを使ったデザインが増えそうです。
CSS clip-path property & CSS Scroll Snap
次は clip-pathとScroll Snapを合わせて紹介します。
clip-pathは好きな形に要素を切り抜ける便利なプロパティで、Scroll Snapはスクロール時の挙動を指定できます。
そしてその二つを組み合わせると、、、パララックス表現が簡単に出来てしまうのです。
同じようなスタイルをbackground-attachment: fixed;で作ることも出来るのですがそちらはsafariが非対応でして、この方式だとレスポンシブでパララックス表現をすることが出来ます。
CSS content-visibility
これはChrome85以降使えるようになったプロパティで他のブラウザのサポートはされていないのですが、かなり革新的なので紹介したいと思います。
上記の記事をまとめると、画面外のコンテンツのlayoutやpaint処理をスキップし、レンダリング速度を向上させてくれるそうです。
使い方は簡単で以下のようにスタイルを指定します。
contain-intrinsic-sizeはcontent-visibilityでレンダリングをスキップする要素の想定出来るサイズを指定します。
.story {
content-visibility: auto;
contain-intrinsic-size: 1000px;
}
これだけで画面外のレンダリングがスキップされるのはすごいですよね。
コンテンツが多いページほど恩恵が大きく、画面のリサイズなどによって発生するレンダリングもスキップされます。
現状chromeしか動かないプロパティなので、CSSに追加しておけば他のブラウザでは解釈出来ないためchromeだけ有効になります。
これだけ便利な機能で他のブラウザにも影響を与えないのであれば、とりあえず追加しておいた方が良い気がしますが、何か懸念事項などないか調べてみました。
以下のサンプルは中のコンテンツに対し、1.5倍のcontain-intrinsic-sizeを取っております。
画面の右手にはセクションに対してのアンカーリンクを用意しました。
上から
・offset 0
・offset3000
・offset3000(JSによるスムーススクロール)
・レンダリングがスキップされたwrapperのテキスト
となっています。
右下にはCLSの値を表示しています。
CLSは cumulative layout shiftの略称でLighthouseにも使われている指標です。広告や画像の読み込みなどで画面がガクッと動くと点数が下がります。
https://web.dev/cls/
CLSの計測には計測用のAPIが用意されているのでそれを使用しました。
https://github.com/WICG/layout-instability
let DCLS = 0;
new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.hadRecentInput)
return; // Ignore shifts after recent input.
DCLS += entry.value;
});
}).observe({type: "layout-shift", buffered: true});
上記のサンプルより以下のことが分かりました。
・通常のアンカーリンクは想定通りの位置に遷移することが出来る
・レンダリングがスキップされた要素の中であっても遷移出来る
・JavaScriptでoffsetを取得した場合、"contain-intrinsic-size"によって影響を受けたoffsetの値が取得される
・"contain-intrinsic-size"によって計算されたoffsetを元にスムーススクロールした場合、画面がガクつく
・ページ表示時に"content-visibility: auto;"が指定され想定と違うサイズの要素が画面内にあった際にCLSの点数が下がる
・"content-visibility: auto;"が指定され想定と違うサイズの要素があった際、表示領域の外であることにもかかわらずスクロールを行うとCLSの点数が下がる
"contain-intrinsic-size"によって仮の高さが与えられているので、スムーススクロールとは相性が悪いようです。画面内に要素が入る時に本来の高さが戻り、画面外に外れると仮の高さに戻るのでガクガクっと画面が動くように見えます。スクロールの終着地点もズレてしまいます。
・ページ表示時に"content-visibility: auto;"が指定され想定と違うサイズの要素が画面内にあった際にCore Web VitalsのCLSの点数が下がる
これはFirstViewにレンダリングをスキップするような要素を入れること自体間違っているので誤ってcontent-visibilityを指定しないしないように気をつけたいですね。
・"content-visibility: auto;"が指定され想定と違うサイズの要素があった際、表示領域の外であることにもかかわらずスクロールを行うとCLSの点数が下がる
こちらに関してはバグとして報告されており修正が進められているようです。
https://bugs.chromium.org/p/chromium/issues/detail?id=1151526&q=content-visibility&can=2
このようにcontent-visibilityは強力な機能な反面、使い方次第では問題を引き起こす可能性があるので慎重に取り入れていきたいですね。
まとめ
IEが無くなると、今まで使えなかった機能が沢山使えるようになるのでとてもありがたいですね。かなり駆け足の紹介になってしまったので、詳しい実装方法などはご自身で調べていただければ幸いです。
そして、残念ながら紹介しきれなかった機能などもありまして、時間があればCSS Variables、CSS Houdiniなどについてまた書きたいと思います。
さいごに
食べログFEチームでは、一緒に楽しくリプレースに取り組んでくれる仲間を大募集中です!
・難しい課題にチーム一丸となって取り組みたい
・柔軟に働ける環境で自分のスキルを活かしたい
・React/TypeScriptでバリバリ開発したい
・レガシーなシステムのリファクタリングがしたい
・アーキテクチャについて探求したい
・食べログというプロダクトに貢献したい
どれかに当てはまった方は以下のリンクを是非御覧ください!
明日は食べログアドベントカレンダー2020の5日目の記事が公開されるのでご期待ください!