avaice's portfolio

avaice's portfolio

に公開

先日所属している大学のLT会で、Webフロントエンド開発をする時に心がけていることについて発表をしてきました。

https://docs.google.com/presentation/d/1b7osHtOBsWznSIce3lQUmU1xFTiJI1NsrrrdgXUf3xc/edit?pli=1#slide=id.g2bc3d58af7a_1_75

今見返してみたら内容が抽象的過ぎて良く分からなかったので、具体的なテクニックを添えつつ、あらためて記事にしてみようと思います。

(これから色々書きますが、あくまで私の考えです。是非コメントやTwitter等で、みなさんの意見も教えてほしいです。)

「良いフロントエンド」とは

一般的に何かプロダクトを開発するときは良いものを作りたいと思うのではないでしょうか?

思いますよね。

フロントエンドを開発するときにも思うはずです。では、「良いフロントエンド」を作る上で大事なことは何でしょう?

安定して動くこと・セキュリティが担保されていること等色々ありますが、私がフロントエンドにおいて特に大事だと思っていることは、以下の3つです。

  • 挙動がわかりやすい
  • 誰でもアクセスできる
  • 速い

次のセクションで、具体的な考えとテクニックについて記していきます。

その1: 挙動がわかりやすい

ユーザーが脳内でなんとなく「ここを押したらこういう挙動をするんだろうなぁ」みたいに思っているであろう挙動に忠実であるべきです。

もちろんコンテンツの方向性にもよりますが、基本的には突飛なものより予測可能なUIにしたほうが良いと私は思います。

テクニック

予測不可能なデザインを避ける

例えば、削除ボタンが緑色だったら、頭が混乱します。押し間違えそうです。

他にも、スクロールバーを動かすとコンテンツ内容が変化するような演出も、混乱を招きがちなのではないかと思っています。(これは賛否両論ありそう...)

ユーザー操作には遅延なく反応を返す

ボタンなどのインタラクション

例えば、あるユーザーが匿名掲示板でレスバトルしていたとします。ユーザーは、自分の意見を書いて意気揚々と「送信」ボタンを押しました。

...3秒くらい待ちましたが、何も画面に変化がありません。もう1回押してみたら、画面が遷移して投稿が完了しましたが、なぜか2重に投稿されていて、ユーザーは赤っ恥です。

これはフロントエンドのインタラクションがサーバーのレスポンス速度に依存していたせいで起こりました。送信ボタンを押した直後に「送信中...」やLoadingのグルグルが表示されていれば、防げた悲劇です。

また、今回のようなフォームの送信は成功したかどうかが重要な情報になりますが、逆にこれがTwitterのいいねボタン等のようなそこまで結果が大事ではないボタンだった場合なら、サーバーサイドの結果を待たずに成功時のインタラクションを行うのも一つの手です。

ユーザー遷移のインタラクション

モダンなフレームワークでは`<Link />`タグ等が用意されていてページ遷移をJavaScript上で行うことが多いです。

しかし、これらを使ってページ遷移を行うときは、ブラウザネイティブのページ遷移と違ってローディングバーが表示されません。そのため、ユーザーはちゃんとリンクをクリックしたか不安になってしまいます。これを解決するために、NProgressのようなローディングバーを表示するライブラリを使ってページ遷移を行っていることをユーザーに使えると親切です。

また、ReactならSuspenseを使って少しでも早く遷移先のページレイアウトを表示できるように工夫することもできます。

ユーザーに余計な情報を伝えない

例えば、あなたはTwitterで素敵な写真をみつけて「いいね」しようと思いました。いいねボタンを押したとたんにボタンが「いいね中...」という表示に切り替わり、数秒後に「いいね完了!」という表示に変わったとします。

とてもご丁寧なUIですが、別にサーバーエラーでいいねに失敗したとしてもデカい代償があるわけでもないので、ユーザーにとってはやかましいだけではないでしょうか?

このように、過剰すぎる情報はユーザーにとってノイズなので、表示は最低限必要な内容だけにすべきだと私は思います。

(※デザイン重視のシンプルなUIにしろという話ではないです。それは良くないと思います。)

レイアウトシフトを避ける

ローディング中に、一回ページにレンダリングされたコンテンツは、それ以降場所が動かないようにするのが理想です。

ですので、レイアウトに影響を与えてしまうような部分はSSRを行ったり、プレースホルダーを置いたりしてレイアウトの変更が極力少ないようにする実装を行うのが良いです。

画像もしっかりWidth, Heightを指定して、読み込みが終わる前からスペースを確保しておきましょう。

ちらつきを減らす

上の項目にも似た内容ですが、ページ読み込み時の画面のちらつきを減らすことでユーザーの混乱を減らすことができます。

例えば、ロゴ画像などFirst Viewの領域にあって絶対表示されるような画像は以下のようにプリロードしてしまうのも一つの選択肢です。

<head>
  <link rel="preload" fetchpriority="high" as="image" href="/logo.png" type="image/png" />
</head>

また、他にも、ロード中にプレースホルダーを多用しすぎるとちらついてしまうので、そのような場合はプレースホルダーではなくLoadingのアニメーションを表示する等のアプローチに変えるのもありだと思います。

その2: 誰でもアクセスできる

Webアプリ・Webページはアクセスしやすい性質上いろいろなユーザーに使われます。そのため、誰でも等しく利用することを担保するアクセシビリティ対応はとても重要だと思います。また、ユーザーにとって公共性の高い(≒使わないといけない)サイトであれば、なおさら重要です。

アクセシビリティというと「障がいを持っている方でも使えるようにする」というのを想起しがちですが、そればかりでもなくて、色飛びしまくるモニターを使っていて薄い色が見えない状況[^1]や、キーボードを使って効率的に操作したい状況などもあり、意外と色々なケースで対応が必要とされています。

以下にアクセシビリティに関する色々なテクニックを紹介していますが、本当に奥深くてまだ私も完全に理解できていません。気になった方はぜひ調べてみてください。

テクニック

適切な代替テキスト

画像にはaltをつけましょう。SAWADA STANDARD DESIGNさんの作成されたチートシートが参考になるのでお勧めです。

https://sawada-std-design.com/works/readable-na/readable-na-alt-decision-tree-20181105.pdf

間違えやすいのが画像ボタンの代替テキストです。例えばゴミ箱( :wastebasket: )アイコンの削除ボタンがあるとします。これの代替テキストは「ゴミ箱」ではなくて「削除」です。

また、画像でなくても、視覚からしか情報が得られないものは`aria-label`等の属性を使って説明できる内容を用意しましょう。[^2]

(ただ、代替テキストは画像の多いコンテンツを製作する場面においてはめちゃくちゃ作業量が増えてしまうので、より良い解決策が出てくれると嬉しいなーと思っています。)

キーボード操作への対応

リセットCSSを使っていると、キーボードフォーカスしたときの見た目の変化が消えてしまいます。これだとどこをフォーカスしているのか分からないので、ちゃんとフォーカス時に見た目の変化が出るようにしましょう。

マウスでフォーカスを当てた時にも見た目に変化が出てしまうのが嫌な場合は、`focus-visible`を使えばキーボードでフォーカスを当てた時しか変化が起こらないように出来ます。

また、タブのUIやダイアログ等もキーボード操作できたほうが良いです。ただ、実装がなかなか面倒なので、そういう時はアクセシブルな実装がされているUIライブラリを使うのが良いと思います。

動的に変更される要素をスクリーンリーダーへ通知する

JavaScriptを使って動的に内容を変更するUIがある場合は、`aria-live`を設定します。通常は`polite`を設定します。

即時に伝えるべき内容の場合は`assertive`を使います。`assertive`にすると、MacのVoiceOverなら「ポロン」みたいな注意を惹く音とともに内容の変更が通知されます。

色使いへの配慮

WebエンジニアはMacを使いがち(偏見かも)なので、それなりに良いモニターで動作を確認していると思いますが、意外とまだまだ世の中には色がきれいに表示されないモニターが存在します。そういった環境でも問題なく使えるように、色遣いを配慮する必要があります。コントラストの確認は、ChromeのDeveloper Toolsで行えます。

↑悪い例

その3: 速い

Webサイトは、ネイティブアプリ等と比べて消費されるスピードが桁違いです。例えばGoogleで「焼肉 おすすめ」みたいに検索するとき、検索結果ページとそこに示されたサイトを何度も行き来すると思います。

このようにWebサイトはインスタントにアクセスされるものです。ネイティブアプリとは違って、何分も腰を据えて読み込みを待ってくれる人は当たり前ですがいません。

逆に言えばWebサイトはそうやって気軽にアクセスしてもらえるのが強みなので、速さが重要だと思っています。

テクニック

バンドルの適切な分割を行う、キャッシュを適切に行う、冗長な技術選定を行わない...等ありますが、この辺りはQiitaに良い記事が沢山あるので、割愛します。

とはいえ完璧にやるのは難しい

フロントエンドエンジニアはよく冗談半分でJSON色付け係などと呼ばれますが、これらすべてを考慮するとなかなか色を付けるのも大変です。私も全部できるように努力していますが、全然完璧ではありません。

それでも今回記した内容を頭の片隅に置いておくと、フロントエンドを実装する際の思想や方向性が定まるので、ぜひ参考にしてみてほしいです。

また、間違っている内容や別の視点があれば是非コメントやTwitter等で教えていただけると幸いです。

[^1]: Backlogの方が作成されたスライドに、めちゃくちゃ参考になる例がありました。(31ページ辺りの「コントラストの問題」というセクション)

https://speakerdeck.com/nulabinc/geeks-who-drink-renewal-design-edition

[^2]: 例えば冒頭で紹介した、私が作った[オンラインで動くリバーシ](https://online-reversi.xyz/)ではコマをCSSで表現しています。これは視覚的にしかわからない内容なので、`aria-label`を付けています。