フロントエンドの話で登壇してきました

by 37108 at 2023/06/26

フロントエンドの仕事から学んだことみたいなテーマで登壇をしました。登壇資料をそのままアップロードするより、参考資料など含め記事にまとめてしたほうがよさそうだったのでここで筆を取っている次第です。一部は既に本サイトで執筆したことがある内容なので省略などしております。

デザインのエッジケースに対処する

デザイナが作成したFigmaなどのワイヤーフレームだけではマークアップの実装に迷いが生じることがあります。 そういったデータは理想的なデバイスサイズでかつ、理想的なデータが入ってくることを想定して作成していることがあるため、実装時に想定していないサイズやデータが入るときに認識齟齬が発生します。エンジニアとしては気を利かせて対応したのにデザイナの意図と異なる実装だったがために修正が入ったり…そういった事象が起こり得ます。

API からデータを受け取ってカードを表示するとしましょう。例えば一番左が理想的な状態でのワイヤーフレームだとして「画像サイズが不適切な場合」と「文字数が不適切な場合」が発生し得ます。

not good wireframe card

「画像サイズが不適切な場合」の対処には object-fit が挙げられます。 object-fit: cover; を指定することで表示領域に画像が収まらない / 部分的にかけるといった場合の対処が可能になります。 object-fit: contain を指定した上で背景色を差し込むことで画像の全体を表示しつつ周りとの違和感を最小に抑えることもできます。

「文字数が不適切な場合」の対処には line-clamp が挙げられます。想定している行数以上になった場合は「…」で表示を切ってしまいます。どこまでも表示するべきなのであればカードの幅より横に行かないようにCSSで制御しつつ表示するのも1つの対処法であります。

またここまで不適切という表現を使ってきましたがユーザが入力できる値である以上、システム的には適切な範囲です。 受け付ける画像サイズを特定のサイズのみにすることや、文字数に制限をかけることでシステムとしても不適切な値にはできますが、ユーザの使い勝手との相談になるでしょう。

他にもさまざまなケースは実際にあったのですが、それをデザイナとエンジニア間でのコミュニケーションを強化するという形で対応してきました。 object-fit での対処は実際に画面を共有しながらどうなるかを打ち合わせたり、 line-clamp での対処はSlack上で確認をとり方針を決めていきました。

またスクラム開発の1スプリントで完璧を求めすぎず、dev環境上で理想状態で動くという60点のゴールから初めて次スプリント以降でレビューで発生した課題を含めて80点、90点…を目指していく形にするなど開発手法の調整でも対処してきました。

より円滑なコミュニケーションを求める

エンジニアとデザイナで仕事の内容は異なりますが、ユーザに良い体験をしてほしいという目標は同じであるはずです。その目標の障壁になっているのがエンジニアとデザイナの考え方の違いなのかと思っています。私がエンジニアでしかないので推量混じりになってしまい申し訳ないです…。

エンジニアはHTMLの構造を変更したら表示が変わること、CSSのプロパティに特定の値を入れたら表示が変わることなど仕様という制約の元で実装を進めます。それに対してデザイナはさまざまな原則(ゲシュタルトの法則 / オッカムの剃刀 …)を判断の指針としてビジネスやユーザの課題を解決を目指してワイヤーフレームを作成します。原則が判断の基準であるので自分の判断でそこから逸脱した箇所を発生させることもできるのでそれで実装が困りそうなのであれば事前に相談や説明を設けたり、相談されたらまず意図を説明した上で実現可能な内容に置き換えるべきでしょう。

特にユーザからデータを受け取って表示することを検討している部分については、その部分で発生し得る内容をワイヤーフレームに詰めるのが良いかと思います。例にだした画像や文字の行数についてコンポーネントの隣にメモを置いたり、Figmaの指定ではみ出したら clamp するといったことも可能なはずなのでそれを入れた上で長い文章を入れて上げるととても親切だと思っています。またチェックボックスのチェックマークや、順序なしリスト要素のドットなどのデザインはワイヤーフレームにあるものを活用してほしいのか、それともブラウザ標準のものを利用して良いが、ワイヤーフレームを作成する都合でこれを利用しているなど、そういった意匠を伝えていただけるとエンジニアは悩まずに済みます。

またエンジニア側もエッジケースがあったときに「この場合のワイヤーフレームをください」とだけ伝えるのではなく、技術的に可能な選択肢を添えてフィードバックするのが良いです。画像の例でいくと、「画像の大きさが理想的でないときに object-fit を使えばうまく収まるんですけどどうでしょうか?」みたいな内容であげればデザイナの仕事を減らすきっかけや、今後どうしていくかのお互いの判断基準が作れたりします。

結局のところプロダクトもデザインも誰か1人が作るものではなく、協力して作るものです。だからこそ対話と共通認識を作り上げましょうということでした。

User Experience の改善

前半部分は Core Web Vitals から調整する画像の改善 の内容を喋ったようなものなので省略します。付け加えるとChrome DevTools (特にLighthouse) が優秀なので早い段階で活用して調整しましょう。後半部分でアニメーションの話をしたのでそれについて書いていきます。

アニメーションのパフォーマンス

仕事で実装したアニメーションのパフォーマンスが良くないとの連絡があった(私の端末では問題なかった)ので、それの対応をしていました。ここから先の画像やコードは仕事とは何も関係のないところで撮影したスクリーンショットなどになります。 まず、Chrome DevTools のPerformanceタブで計測してさまざまな情報が観れます。Summaryタブで処理にかかった時間が、Event Logで発生したことがわかります。

Chrome DevTools Performance Summary

CSS アニメーションがパフォーマンスに与える影響箇所としてRendering と Paint があります。なので個々の処理を減らしていくのが重要になります。 結論を先に書くと、 transformopacity を利用してアニメーションを作るようにするとRendering と Paintが最小限に抑えられます。それ以外のプロパティでアニメーションをする時はよく観察して問題ないかを適切に見極める必要があります。

下記コードのように position を利用したアニメーションの場合、要素が動くたびに Paint が発生するため処理負荷が高くなってしまいます。

.container {
  position: absolute;
  width: 240px;
  height: 240px;
  background-color: rebeccapurple;
  animation: slide 3s infinite;
}

@keyframes slide {
  from {
    left: 100%;
  }
  to {
    left: 0;
  }
}

実際の Event Log は下記になります。re-paint が頻発しているのがわかると思います。

Chrome DevTools Performance Summary

それ以外の要素がほとんどなければ問題ないかもしれませんが、他の要素や処理がたくさんあると確実にパフォーマンスの悪化につながるでしょう。 それに対して transform を利用した場合はPaint 処理が最小限に抑えられます。

@keyframes slide {
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}

実際の Event Log でも最小限の re-paint で済んでいます。

Chrome DevTools Performance Summary

これはレイヤという概念が大きな影響を及ぼしています。アニメーションの対象要素がブラウザ上で生成されたレイヤに送られます。レイヤに送られた要素は独立して処理がされて最終的に合成されて画面上に描写されます。paint という重い処理をレイヤに分離させることでパフォーマンスの改善が見込まれるわけです。ついでにレイヤでの処理にはGPUが使用されるのでより良いわけです。

ページ上の要素に対し何らかの指示(例えば、3D transforms)を与えた時、その要素は自身の“レイヤー”に送られ、そのレイヤー内で、ページ上の他の要素とは独立してレンダリングされます。その後、その要素がページ内に合成されます(つまり画面上に描画される)。

レイヤに分離して処理をさせればパフォーマンスが改善されて transformopacity プロパティを利用するとレイヤが生成されるからパフォーマンスが改善されるというのがここまでの内容です。 ただし、GPU がグラフィック処理が得意だからといってアニメーションの全てをGPUで処理すれば良いかと言われるとそこもまた一概に言えないのが難しい部分です…。レイヤ処理のためにはGPUのメモリを消費します。もしGPUのメモリが限られている場合に、大量のレイヤ生成がメモリをたくさん消費してかえってパフォーマンスを悪化させたり、CPUとGPU間での帯域幅があまり太くない場合にはそのやり取りにも時間がかかってしまいます。 どうすればいいんだろうという気持ちになりますが、アニメーションが発生しない要素でかつ、代替案がある場合は opacitytransform といったプロパティを避ける (opacity の代わりに rgba など…) ことが挙げられますがそれで実際にどこまで改善できるだろうかという複雑な心中です。あとはOSや端末についてどのくらいのスペックまでフォローするかどうかといったベースラインの策定をすることで割り切るのも1つの手段かと思います。

まとめ

無理くりまとめてしまうと、

さいごに

デザイナとの協業、UXの改善、テストについて登壇では喋ってきました。テスト部分は以前ブログを書いたのでざっくり省いて、まだ書いてないデザイナとの協業とアニメーションのパフォーマンスについて書いていきました。アニメーションというかパフォーマンスについては方法論はわかるけど、実際どうするのが良いかが難しいという結論になってしまい悲しい気持ちでいっぱいです…。いつか最適化手法をより詳しくまとめられたら書こうかなぁという気持ちです。

参考資料