Open8

2022年に駆け出しエンジニアがフロントエンドを学ぶとしたら(やるべきこと)

Every LayoutでCSSによるレイアウトのパターンを学ぶ

Every Layout日本語版もあります)というテキストで、CSSを使ったレイアウトの方法を学びます。

注意点: Tailwind CSSと組み合わせては使えない(たぶん)

Every Layoutで説明されているレイアウトのパターンは、継承などのCSSの特徴を最大限に活かして、最小限のスタイル定義で済むようになっています。近年のフロントエンド開発で積極的に採用されているTailwind CSSでは、そのまま使えないパターンが多いでしょう。

Every Layoutの本文においては、utility-first CSSについて以下のように言及されています。

In a utility first approach to CSS, inherited, universal, and element styles are not really leveraged at all. Instead, combinations of individual styles are applied on a case-by-case basis to individual and independent elements.

There may be reasons, under specific circumstances, why one might want to go this way. Perhaps there is a great deal of detail and disparity in the visual design that benefits from having this kind of granular control, or perhaps you want to prototype something quickly without context switching between CSS and HTML. Every Layout's approach assumes you want to create robustness and consistency with the minimum of manual intervention. Hence, the concepts and techniques laid out here leverage axioms, primitives, and the styling algorithms that extrapolate from them instead.

CSSへのユーティリティファーストアプローチでは、継承されたスタイル、ユニバーサルスタイル、および要素スタイルは実際にはまったく活用されません。代わりに、個々のスタイルの組み合わせは、個々の要素と独立した要素にケースバイケースで適用されます。

特定の状況下では、なぜ人がこの道を進みたいのかという理由があるかもしれません。ビジュアルデザインには、この種のきめ細かなコントロールの恩恵を受ける細部と格差がかなりあるかもしれませんし、CSSとHTMLの間でコンテキストを切り替えることなく、何かをすばやくプロトタイプ化したいかもしれません。すべてのレイアウトのアプローチは、最小限の手動介入で堅牢性と一貫性を作成したいことを前提としています。したがって、ここで説明する概念とテクニックは、公理、プリミティブ、およびそれらから外挿するスタイルアルゴリズムを活用しています。(翻訳はDeepLの結果をそのまま載せています)

現実的な判断としては、実際のフロントエンド開発においてはCSSを直接書かずにTailwindを使うことになると思います。ですので、Every Layoutのパターンを習得しても実際のプロジェクトには使えないということになります。とはいえ、Tailwindのようなアプローチが今後永遠に主流であり続けるかどうかはわかりませんし、TailwindはCSSに基づいているので、Tailwindよりもまず素のCSSの使い方を覚えたほうがいいのでは?と思います。Every LayoutとTailwindの両方をやります。二度手間になっても、確実で正しい学習順序を取る方針です。

Follow-up

テキストを読んだ後は、こちらの課題を実践します。

Every Layoutを使ったCSSレイアウトの実践

Every Layoutで説明されているレイアウトのパターンを実際に練習します。CSSの一番低いレベルの課題です。

題材

最初はTailwindを使わないでCSSを練習すると宣言しましたが、レイアウトの練習をするための素材としてはTailwindに関係するものが豊富です。たとえば以下のTailwind UIというライブラリのサイトでは、実際のウェブサイトやアプリケーションで用いられる豊富なレイアウトのパターンが、Marketing、Application UI、Ecommerceというカテゴリーに分類されてサンプルと一緒に示されています。これらのパターンを実装できるようになることが、CSS習得の主要な目標の一つであるはずです。

Tailwind UI - Official Tailwind CSS Components

レイアウトの素晴らしいショーケースであるTailwind UIですが、これを実際にCSS初心者が練習のために実装しようとする場合、以下の難点があります。

  • 一部のサンプルについては、本物のHTMLではなくキャプチャした画像として示されている。そのため、ウィンドウの幅を変更したときのレイアウトの変化などがわからない。
  • 粒度(fidelty)が高すぎる。厳密に同じ見た目のものを作ろうとすると、design tokensも用意しなければならないため、レイアウトの練習という目的を逸脱してしまう。

なので今回は、代わりにTailblocksのレイアウトをCSSで再現する練習することにしました。これならどのレイアウトも本物のHTMLが見本として示されているので、ウィンドウの幅を変更したときにどんな振る舞いをするように実装しなければならないかを確認できます。しかもどの見本も「粗い」ので、細かいことは気にせずにレイアウトだけに集中できます。(ちなみにこんな感じのテンプレート集は、20+ Free Tailwind CSS Templates And Tools - UIdeck で多数紹介されています。)

手順

余白や文字サイズ、breakpointなどは適当に、レイアウトだけを再現していきます。(もちろん実際のプロジェクトでは適当にやったらだめです。最初の練習だけです。)

練習用のプロジェクトをセットアップするには、Reactの場合はViteを使うのが簡単です。CSSの表示確認をするだけなので、React + TypeScriptの最小限のテンプレートで十分です。とはいえ、Reactはscoped CSSが組込みではないので、単にCSSを書いてimportしていくだけだと複数のページのスタイルが混ざってしまいます。今回の練習にはSvelteを使うほうがいいかもしれません。

反省

Tailblocksのレイアウトはブレークポイント(@mediaクエリ)を多用しています。Every Layoutにおいては、ブレークポイントを使わずにレイアウトを切り替える Switcher というパターン (The Flexbox Holy Albatrossに詳しい説明があります) が紹介されており、このテクニックを使うことで概ね同じレイアウトを再現できるのですが、それでもTailblocksと全く同じレイアウトを再現することはできないことがわかりました。

というのも、Tailblocksの見本は文字を中央揃えにしたり、グリッドのカラム数が偶数値になるように固定値を指定したりといったように、ブレークポイントに応じて細かいスタイルの制御をしています。試してみましたが、@mediaクエリ(または@containerクエリ)やJavaScriptを一切使わずに、viewportの幅を変えたときの振る舞いを忠実に再現するのはどうやら無理そうだということがわかりました。

また、Tailblocksの見本のほとんどは同じパターンの繰り返しなので、始めてみるとすぐに飽きます。各カテゴリーから1個ずつ拾って練習してみようかと思いましたが、そこまでやる意味さえもなさそうなので、この課題は中止にします。

今回の課題をこなす中で、flexboxとgridがどんな場面で使えるかはわかるようになりました。Every Layoutのすべてのパターンに習熟できたかというと、一度も使ったことがないパターンもあり、練習は足りていません。Tailblocksの見本だけでは問題のバリエーションが足りないと思います。本格的なアプリケーションUIを実装していれば、どのパターンもいずれは使う機会があるのでしょう。

いずれにせよ、ここからスキルを上げるには、スタイルガイドやアセット等が準備されている正式の練習課題をこなす必要がありそうです。以前 16 front-end projects (with designs) to help improve your coding skills - DEV Community の課題をこなそうとしたときは、まだ基本的なスキルが足りていないと思いましたが、今なら取り組めそうです。

今回Tailblocksの見本においては、Cardが多用されていました。Cardは実際のアプリケーションUIにも非常に多く見られます。以下のチュートリアルのようにChakra UIを使ったり、Tailwindで実装したりすることになるでしょう。早くTailwindに慣れたほうがいいと思いました。

How to Create Modern Cards in Chakra UI & React JS ⚡️

Cardのコンポーネントは画像やビデオが含まれていることが多く、テキストの長さによってレイアウトが崩れたりもします。Every Layoutに挙げられている基本的なレイアウトパターンの知識だけでなく、以下の記事で説明されているようなUX上の配慮が必要になると思われます。

Developer Decisions For Building Flexible Components — Smashing Magazine

Follow-up

Every Layoutに特化した(?)練習は終わりです。

まだCSSの練習は足りていないので、16 front-end projects (with designs) to help improve your coding skills - DEV CommunityのNewbie〜Junior、もしくは同等の課題をこなす必要があります。Tailwindを使わずに素のCSSを書く場合は、Every Layoutのパターンを使う機会もあると思います。(Tailwindを使う場合も一部はEvery Layoutの考え方を応用できると思います。)

追記

Follow-upに書いた通り、16 front-end projectsに挙げられているFrontend Mentorの課題を何個か拾って取り組んでいます。たとえば Pricing Component with Toggle は以下のように実装できました。(動画がちらついていますが、私の収録環境の問題でありCSSのせいではありません)

以下のリソースで勉強すれば、このレベルの課題に必要なスキルはほぼ習得できます。

JavaScriptを使わずに年額と月額の金額表示を切り替える方法はググりました。フォントもMontserratが私のLinux環境にインストールされていなかったので、フォントにリンクするためのコードをGoogle Fontsで生成して貼り付けました。デザインと若干違う点もありますが、練習なのでこれでよしとします。

実際のプロジェクトに取り組むとしたら、Figmaなどのデザインを参照しながらコーディングしていくことになるので、Figmaなどのツールの使い方を修得する必要があります。(Frontend Mentorでは月12ドルのProプランを契約すればSketchとFigmaのファイルも月5個までダウンロードできるようです。)

あとは保守性を考えるとCSSの管理が問題です。BEMやITCSSCUBE CSSRSCSSといった、2010年代から提案されてきたCSS方法論で命名規則やファイル構成を統一したり、Tailwind CSSやCSS-in-JSなどのフレームワークを導入してスタイルを直截に指定していくなどの方法があります。

今はcomponent-drivenの時代ですし、コンポーネントのスタイルはコンポーネントになるべく近いところに記述し(Vue.jsやSvelteならばscoped CSSも組み込みで備わっている)、その他のスタイルはstyle guide + design tokensとして集中管理する(全体としてdesign systemを構成する)という方針で大雑把には決着がついているようですが、依然としてニュアンスは残ります。どうやって開発を進めていくかという組織的な問題や技術選択とも関係するので、判断には経験が必要でしょう。

UIデザインの原則を学ぶ

Refactoring UI を読み、エンジニアでも見栄えのするデザインをするために必要なテクニックを学びます。

本の値段が高い

Goodreadsで現在4.68点という高評価を得ているRefactoring UIですが、値段が99ドルと高いです。これに9.99ドルの税金を加え、1ドル約130円の現在の為替レートにクレジットカードの為替手数料を加えると、なんと15,000円近くにもなってしまいます。デザインの本は全体的に値段が高い気もしますが、それにしても高いです。もっと安い本で、同等の内容を網羅しているものがあれば、そのほうがいいと思います。

デザインしなくても知っておくべき

ウェブ制作のプロジェクトに入ると、コーダーはデザイナーがデザインしたものを忠実に実装することが要求されます。恥ずかしながら私は不得意だったので、私にはこのタスクはほとんど振られませんでした。CSSのコーディングを専門にしたいとは思いませんが、デザインのコーディングができないと、フロントエンドエンジニアとしてできる仕事が限られてしまいます。一人で全部できない人は使いにくいです。つまり失業につながります。

Refactoring UI を読んでみて、これはデザインしない人も前提知識として押さえておくべき内容だと思いました。たとえばCSSには box-shadow というプロパティがありますが、CSSの仕様を知るだけでは、どう使うべきかわかりません。Refactoring UIではデザインとCSSの対応が示されています。

ネットで調べれば資料はたくさんあるでしょうが、初心者が手探りで学ぶのは厳しいものがあります。

あの本よりは充実している

エンジニアに推薦されるデザインの本というと、00年代から Non-Designer's Design Book が有名です。私も読んだことがあります。内容は出版物の余白やtypographyに関することが主であり、UIデザインに関することはほとんど書かれていなかったと記憶しています。なぜこの本がおすすめされているのか不思議でした。

Non-Designer's Design Book と比べると、 Refactoring UI はちゃんとUIデザインに関することが書かれています。デザインについて全くの素人がフロントエンドエンジニアを目指すのであれば、一冊目として手に取る本として Refactoring UI は全く見当違いな本ではなさそうです。

Follow-up

この本で解説されているテクニックを、CSSを使って実装する練習をしようと思います。(詳細未定)

WAI-ARIA

WAI-ARIA Authoring Practices 1.2 を読みます。

新たにARIA Authoring Practices Guide Homeのサイトができ、Authoring Practicesのドキュメントは廃止されたようです。

WAI-ARIAとは

WAIは Web Accessibility Initiative の略称であり、World Wide Webのaccessibilityを改善するための活動をしています(参考文献)。

ARIAは accessible rich internet applications の略です。Accessible Rich Internet Applications (WAI-ARIA) 1.2 がARIAのモデルを定義する仕様であり、Authoring PracticesはHTMLのマークアップについて説明しています。

No ARIA is better than Bad ARIA

Authoring Practices第2章のRead Me Firstには、“No ARIA is better than Bad ARIA”として、以下のように述べられています。

Functionally, ARIA roles, states, and properties are analogous to a CSS for assistive technologies. For screen reader users, ARIA controls the rendering of their non-visual experience. Incorrect ARIA misrepresents visual experiences, with potentially devastating effects on their corresponding non-visual experiences.

機能的には、ARIAの役割、状態、およびプロパティは、支援技術のためのCSSに類似しています。スクリーン・リーダーのユーザーにとって、ARIAは、非視覚的な体験のレンダリングを制御します。不正確なARIAは、視覚的体験を誤って表現し、対応する非視覚的体験に壊滅的な影響を与える可能性があります。(翻訳はDeepLの結果をそのまま載せています)

accessibilityは視覚障害者をはじめとする障害者にもウェブを閲覧できるようにしようというものですが、ARIAの機能を正しく理解しないで間違った使い方をしてしまうと、健常者には想像しがたい苦しみを与えてしまうことになるようです。

ARIA対応のコンポーネントを使う

ARIAを使ったコンポーネントは、第3章にて色々と紹介されていますが、これを実装するのは大変そうですし、間違った実装は障害者にとって大変危険です。

一般的に推奨されているのは、ARIA対応のライブラリを使うことです。You Don’t Need A UI Framework — Smashing Magazineでは、以下のライブラリがおすすめされています。

この中で私は(Reactプロジェクトの場合)React Ariaを使うのがよさそうだと思いました。コンポーネントライブラリというよりはReactのフックの集まりであり、コンポーネントの見た目は自由にできます。Radix Primitivesもスタイルは自由にできますが、React AriaはAdobeが開発しており、ドキュメントが非常に詳細です。accessibilityについて厳格な品質基準を適用しなければならないプロジェクトには特に、React Ariaのほうがよさそうです。

Headless UIはTailwind CSSのTailwind Labsから出ているので、Tailwindの熱心な支持者にはアピールするかもしれませんが、コンポーネントの数が少なく(これでも大抵のプロジェクトには十分かもしれませんが)、Radix Primitivesのほうがよさそうに見えます。

ちなみにHacker Newsにも半年前のスレッドがあり、以下の通りReact Ariaは高評価です。

I've been using react-aria on a personal project, as well as building a UI library at work based on TailwindCSS+React Aria. I generally really like the combination. The maintainers are super responsive+helpful on Github and really know how to engage constructively with criticism. I really appreciate what they're doing. The combination of TailwindCSS+React Aria provides one with a pretty great template/scaffolding for building out a fully featured component library.
私は個人的なプロジェクトでreact-ariaを使い、また仕事ではTailwindCSS+React AriaをベースにUIライブラリを構築しています。私はこの組み合わせをとても気に入っています。メンテナはGithub上で非常に反応が良く、手助けしてくれますし、批判に対して建設的に取り組む方法を本当によく知っています。彼らがやっていることには本当に感謝しています。TailwindCSS+React Ariaの組み合わせは、フル機能のコンポーネントライブラリを構築するための非常に優れたテンプレート/足場を提供します。

react-aria is awesome. You structure your DOM and css however you want, and react-aria provides hooks that return props to spread onto your elements to make them come alive. These same hooks also give you visibility into and control of the component state, so you can also easily blend in your own custom logic for the component. It is about as flexible as a headless ui library can get. But it's also lower level and so harder to use than, say, radix primitives.
react-ariaは素晴らしい。DOMとCSSを好きなように構成し、react-ariaはプロップを返すフックを提供し、要素を生き生きとさせることができます。これらのフックは、コンポーネントの状態を可視化し、コントロールすることもできるので、独自のカスタムロジックをコンポーネントに組み込むことも簡単にできます。ヘッドレスUIライブラリの中では、最も柔軟性の高いものです。しかし、低レベルなので、例えばradixプリミティブのようなものよりも使いにくいです。

Authoring Practicesのドキュメントは第3章以外一通り目を通しましたが、実際の開発にはライブラリを使うことにします。

Follow-up

練習のプロジェクトでReact AriaとTailwind CSSを組み合わせて使ってみることにします。もしHacker NewsのスレッドでコメントがあるようにReact Ariaが使いにくければ、Radix Primitivesのほうがいいかもしれません。

Anti-Design

2022年から顕著になってきた新しいデザインの流れとして、 anti-design があります。

Designers are taught that simple, intuitive and frictionless design is the key to a good user experience. The idea is that, while users want to see aesthetically pleasing websites, they don’t want to be distracted or have obstacles put in their way that could disrupt their journey on the website. Any extraneous design elements should be avoided.

Anti-design is an approach that bucks the rules of conventional design in favor of challenging, experimental layouts. In web design, this means doing away with the clean, symmetrical, grid-based layouts so commonly seen in today’s websites in favor of loud colors, crowded, asymmetrical design. Anti-design encourages exploration and experimentation, and is meant to push the boundaries of what it means to be a useful and engaging website.

これまでのデザインはユーザの邪魔をしないことを重視してきましたが、 anti-design は観客に印象づけるために奇抜なことをしてみようという試みであるようです。

具体的には、以下の記事で紹介されているようなデザインが新たに流行しています。

関連する技術としては、 Variable FontsCSS Text Animations などがあります。

20年以上昔に人々が Flash を使って実現していたことを繰り返しているような感もあります。今度はCSSで実装されているので accessibility の問題は発生しないでしょう。とはいえ、 UI/UX で有名な Nielsen Norman Group の Kate Moran 氏はこのトレンドに反対しています。

機能性を重視するエンジニアが手を出すべき領域ではないと思いますが、デザインと実装技術の両方に通じたアーティスト(?)みたいな人たちは興味を持つかもしれません。

React の基礎知識

Reactでアプリケーションを書き始める前に、Reactについての基礎知識を確認します。アプリケーションの中心はデータであるという信念に基づき、まず初めにReactとデータの基本的な関係を理解します。

React とは何なのか

Reactの最初のバージョンがリリースされた2013年には、Reactの開発チームはReactを次のように定義していました。

React isn’t an MVC framework. React is a library for building composable user interfaces. It encourages the creation of reusable UI components which present data that changes over time.

Why did we build React? – React Blog

ReactはUIを組み立てるためのライブラリであり、最も一般的な使い方は、"React as a view library"、つまりReactをデータを表示するためのライブラリとして使うということであるようです。

React単体としてはMVCフレームワークではないものの、たとえばReactとReduxを組み合わせることでMVCフレームワークを構成することができます。

Reactの世界では、"UI is a function of state"という見方もあります。Reactにおいてそれぞれのコンポーネントは、プロパティを引数として取りマークアップを返す関数です。

UI=F(S)

一方Reduxのreducerは、状態とアクションから新しい状態を返す関数です。ReactとReduxを組み合わせることで、UIは、初期状態、状態遷移の関数、およびコンポーネント関数として定義することができます

S=R(S0, action)
UI=F(R(S, action))

先日の Reactathon 2022 では、 Goodbye, useEffect と題したスピーチがありました。発表者である David Khourshid は、状態機械 (statecharts) を中心とした状態管理のライブラリであるXStateを開発しているStatelyの創業者です。Davidもまた、UI is a function of stateの見方を受け入れています。このスピーチで紹介されていたのは、UIの状態遷移に関する次の図式です。

(state, event) -> (nextState, effects)

既に示したReact+Reduxのモデルと比べてこの図式が優れているのは、状態遷移に伴うUIの変化や様々な副作用をeffectsとして捉えている点です。UI is a function of stateであり、状態は前の状態とaction/eventの関数ですが、実際のアプリケーションのコンポーネントは、単に状態に対するマークアップを返すだけでなく、イベントハンドラを管理したりといった様々なお仕事を担っています。既に示したReact+Reduxのモデルではこれを捉えきれておらず、モデルとして不完全でした。

私が最近のウェブアプリケーションに関して抱いているささやかな不満は、フロントエンドの些細なバグが多いことです。もちろん大規模なサービスであれば致命的な不具合のほとんどはすぐに解決されるでしょうが、通知状態が正しく更新されないといったバグはGAFAMのサービスでも案外残っていたりします。これらのアプリケーションのフロントエンドはReactなどで実装されているはずです。原因はUIの状態の不整合であり、広義にはデータの同期の問題でしょう。

Davidは状態管理(state management)を発展させたstate orchestrationという概念を提示しています(下画像)。XStateが解決策であるかどうかは判断できないものの、モデルとしてはより包括的で一貫しています。データを中心とした一貫したモデルに基づく宣言的なプログラミングは、フロントエンドにおいても理想であるはずです。Davidのこの見方を前提として踏まえたいです。

レンダリングとデータ取得の仕組み

Reactでperformantなフロントエンドのコードを書くためには、Reactのレンダリングの仕組みを理解しておくことが望ましいです。Reactの仮想DOMとレンダリングの仕組みについては次の記事が詳しいです。

もう一つ重要なのは、データ読み込みの戦略です。大きく分けて以下の3種類があります。

  • Fetch-on-Render (Render-Fetch Waterfall)
  • Fetch-Then-Render
  • Render-as-You-Fetch

以下の図で示されているように、最初のレンダリングまでの時間はFetch-Then-RenderおよびRender-as-You-Fetchが速く、ユーザ体験が優れています。RemixではFetch-Then-Renderがデフォルトです。


(出典: How to improve developer experience with React Suspense in Concurrent Mode - LogRocket Blog

Reactの外側の部分、というより一般的なウェブページのレンダリングはどうなっていたかというと、Critical Rendering Pathのようになっていました。UXの重要な指標であるCore Web Vitalsを改善するためにやるべきことの一つとして、このCritical Rendering Pathに基づいて最適化を実施する方法があります。

近年はブラウザの機能がますます高度になり、 Multi Page Application (MPA) においてもページ遷移を速く滑らかにするための様々なテクニックを利用することができます。Turbolink 改め Turbo のようなプロジェクトもあります。ユーザ体験のために必ずしもSPAにしなければならないという時代ではなくなりつつあります。

Follow-up

これらの知識を踏まえた上で、React標準のhooksの使い方を確認します。

作成者以外のコメントは許可されていません