第4章 レスポンシブ設計
画面サイズによる変化も、どの境界の構造が変化するかによって責務を決めます。
「レスポンシブ対応をどこに書くか」は、CSS のメディアクエリをどのファイルに置くかという話ではなく、どの単位がその変化を知るべきかという話です。
Island 内部のレスポンシブ
Section titled “Island 内部のレスポンシブ”ひとつの Island の内部だけでレイアウトが変化する場合、その Island 自身が責務を持ちます。
たとえばカンバンが、利用可能な横幅に応じて列の配置を変更するとします。
Wide
KanbanIsland[ Todo ][ Doing ][ Done ]Narrow
KanbanIsland[ Todo ][ Doing ][ Done ]機能そのものや、他の Island との関係は変わっていません。変化しているのは KanbanIsland 内部の表現だけなので、Scaffold がその詳細を知る必要はありません。
Island は、自身に与えられた利用可能領域に応じて内部構造を適応できます。ここで見るのは画面全体の幅ではなく、自分に割り当てられた幅です。同じカンバンが、広い画面のサイドパネルに置かれることも、狭い画面の全幅に置かれることもあります。画面幅で判断すると、この2つを区別できません。
「自分に割り当てられた幅」を知る仕組みは、どの環境にも用意されています。CSS のコンテナクエリ、Flutter の LayoutBuilder、ResizeObserver などがそれにあたります。名前と使い方は環境ごとに違いますが、親から与えられたサイズを測って分岐するという点は共通です。
画面幅を見るメディアクエリしか使ったことがない場合、ここが切り替えの分かれ目になります。メディアクエリは Scaffold の道具、コンテナ単位の測定は Island の道具、と対応させると迷いません。
Island 間のレスポンシブ
Section titled “Island 間のレスポンシブ”複数の Island の位置、表示方法、可視性などが変化する場合は、Scaffold が責務を持ちます。
デスクトップでは、タイムラインとスレッドを横に並べ、右端にトレンドを置きます。
Desktop
TimelineScaffold┌────────────────┬──────────────┬──────────────┐│ TimelineIsland │ ThreadIsland │ TrendsIsland │└────────────────┴──────────────┴──────────────┘モバイルでは、タイムラインだけを表示し、スレッドは別の画面へ切り替えます。トレンドは表示しません。
Mobile
TimelineScaffold┌─────────────────────┐│ TimelineIsland │└─────────────────────┘
ThreadIsland → Page / SheetTrendsIsland → 表示しないここでは2種類の変化が起きています。ThreadIsland は表示される場所が変わり、TrendsIsland はそもそも表示されなくなりました。 どちらも Scaffold の判断です。
Island を表示するかどうかは、その Island 自身では決められません。TrendsIsland に「画面が狭いときは自分を描かない」と書くと、狭い領域に置きたい別の画面へ持っていったときに、何も表示されない Island になります。自分が要るかどうかを自分で判断させない、というのがここでの分かれ目です。
いずれの場合も、ThreadIsland と TrendsIsland 自身の機能は変わっていません。1件の投稿と返信を見せる責務も、内部の状態も同じです。
変化しているのは、Island が画面上でどのように構成されるかです。そのため Scaffold が判断します。
ThreadIsland の内部に「自分がページとして開かれているのか、横並びの中央にいるのか」を判断するコードを書くと、その Island は画面のレイアウト方針に依存します。別の画面へ移したときに、その判断が意味を失います。
責務の分かれ目
Section titled “責務の分かれ目”Island内部の変化→ Island
Island同士の空間的な関係の変化→ ScaffoldBridge はレスポンシブレイアウトを扱わない
Section titled “Bridge はレスポンシブレイアウトを扱わない”Bridge は論理的な協調境界なので、画面サイズに応じた配置変更は担当しません。
PostSelectionBridge├─ TimelineIsland└─ ThreadIslandという関係は、デスクトップでもモバイルでも維持できます。
デスクトップでは2つの Island が並んでいて、
[ Timeline ][ Thread ]モバイルでは別々の画面に表示されていても、
[ Timeline ]
Thread → PageSelectedPostId を共有するという論理的な関係は同じです。
つまり、
Bridgeは論理的な関係を構成し、Scaffoldは空間的な関係を構成する。
レスポンシブによって描画構造が変化しても、機能間の関係まで変更する必要はありません。
この性質には実装上の利点があります。Bridge が Scaffold の内側で Island を包む位置にいれば、Scaffold がデスクトップ用とモバイル用のどちらのレイアウトを選んでも、Island は同じ Bridge から値を受け取ります。レイアウトを切り替えたときに SelectedPostId が失われる、という問題が起きません。
この要素の内部だけが変わるか?→ その要素自身
複数Islandの配置関係が変わるか?→ Scaffold
Island同士の論理関係が変わるか?→ Bridge3つ目に当てはまるケースはまれです。画面幅によって「共有していた状態を共有しなくなる」ことは、通常はありません。もし当てはまる場合は、それはレスポンシブ対応ではなく、画面幅ごとに別の機能を提供している可能性があります。