ハイライト
Safari 26.4 は
display: grid-lanesを導入し、JavaScript の masonry ライブラリを 3 行の CSS で置き換えます。さらにflow-toleranceプロパティにより、DOM 順と視覚順がずれることで起きるキーボードフォーカスのジャンプを解決します。
主要内容
masonry レイアウトの苦しさ
画像ウォールやカードストリームを作ったことがある開発者なら、この状況を経験しています。画像の高さはまちまちで、Flexbox では大きな空白が残り、CSS Grid では各画像を同じ高さのセルに押し込む必要があります。よくある 3 つの妥協策も理想的ではありません。引き伸ばせば変形し、縮小すればはみ出し、切り抜けば内容が失われます。結局、多くの人は JavaScript ライブラリを導入し、クライアントで各画像の高さを計算して動的に配置します。この方法は動きますが、スクリプトサイズと実行時コストが増え、特にモバイルでのスクロール時に負担になります。
(00:57)
Grid Lanes の位置付け
CSS の既存レイアウトモードは、同じ問いに異なる形で答えています。要素をどこに置き、どれだけの空間を占めるべきか、という問いです。Flexbox は 1 つの軸だけを制御します。コンテンツは 1 本のトラックに沿って流れ、折り返した後も同じ方向に並びます。Grid は 2 つの軸を制御し、行と列が交差するセルに要素を置きます。Grid Lanes はその中間にあります。片方の軸だけを固定し、もう片方の軸はコンテンツ自身の自然な高さや幅に任せます。
(01:13)
結果として、要素は複数のレーンへ分配され、各レーンが独立して高さを計算します。ブラウザは新しい要素を現在最も短い列へ配置し、後続の要素が下側の隙間を埋めていきます。この「最短優先」アルゴリズムにより、各要素の自然な比率を保ったまま、密度の高い配置が自然に実現されます。
(03:07)
masonry からレンガ壁へ、1 つのプロパティを変えるだけ
Grid Lanes は 2 種類の見た目をサポートします。デフォルトは masonry です。列トラックを定義し、コンテンツは上から下へ各列を埋めます。grid-template-columns を grid-template-rows に置き換えると、レイアウトはすぐ横方向のレンガ壁になります。要素は左から右へ、行ごとに流れます。2 つのモードは同じ構文を共有するため、切り替えのコストは非常に低いです。
(04:31)
flow-tolerance がアクセシビリティの痛点を解く
Grid Lanes が Accessibility & Inclusion のトラックに入っている大きな理由は、flow-tolerance プロパティです。従来の「最短優先」アルゴリズムには副作用があります。隣り合う列の高さが近い場合、次の要素が右側の短い列へ飛び、視覚順と DOM 順がずれることがあります。キーボードユーザーが Tab キーを押すと、フォーカスが画面上を左右に跳ね、スクリーンリーダーが読み上げる順序も分かりにくくなります。
flow-tolerance のデフォルト値は 1em です。ルールは、より高い列と最短列の高さ差が許容範囲内なら、絶対に最短の列を追うのではなく、DOM 順で先に来る列を優先する、というものです。この小さな視覚上の妥協により、線形の読書順と安定したフォーカス経路が得られます。
(07:15)
詳細
Grid Lanes コンテナを作成する
(03:58)
最小の宣言は 1 つのプロパティだけです。
.container {
display: grid-lanes;
}
列定義と間隔を追加します。
.container {
display: grid-lanes;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
ポイント:
display: grid-lanesは新しいレイアウトモードを有効にし、display: gridと並ぶ構文ですrepeat(3, 1fr)はコンテナ幅を 3 等分します。frは fractional unit の略ですgap: 10pxの書き方は CSS Grid と完全に同じですgrid-template-columnsまたはgrid-template-rowsのどちらか一方だけを定義できます。両方同時には使えません
レンガ壁バリアント
(04:33)
列定義を行定義へ置き換えると、masonry はレンガ壁になります。
.container {
display: grid-lanes;
grid-template-rows: repeat(3, 1fr);
gap: 10px;
}
ポイント:
grid-template-rowsがgrid-template-columnsを置き換える- 要素は行方向に流れ、横方向の並びを形成する
- 方向はどちらか一方を選び、混在はできない
レスポンシブな列幅
(05:10)
何列入るかをブラウザに自動判断させます。
.container {
display: grid-lanes;
grid-template-columns:
repeat(auto-fill, minmax(200px, 1fr));
gap: 10px;
}
より複雑な繰り返しパターンです。
.container {
display: grid-lanes;
grid-template-columns:
repeat(auto-fill,
minmax(8rem, 1fr)
minmax(14rem, 2fr));
gap: 10px;
}
ポイント:
auto-fillはコンテナ幅に応じて、できるだけ多くの列を作るminmax(200px, 1fr)は各列を少なくとも 200px にし、残りの空間を均等に分ける- 幅の狭い列と広い列が交互に現れるような繰り返しパターンも定義できる
個別要素を制御する
(05:45)
ある要素を 2 列にまたがらせます。
.container {
display: grid-lanes;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
}
.item {
grid-column: span 2;
}
開始位置を正確に指定します。
.item {
grid-column: 2 / span 2;
}
ポイント:
grid-column: span 2は列方向に 2 つのセルをまたぐgrid-column: 2 / span 2は第 2 列から始まり、2 列にまたがる- 列位置は制御できるが、行位置は Grid Lanes が自動計算する
Subgrid と統合する
(06:22)
2 列にまたがるカードの内部要素を、親グリッドに揃えます。
.container {
display: grid-lanes;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
}
.item {
display: grid-lanes;
grid-template-columns: subgrid;
grid-column: span 2;
}
通常の Grid をネストすることもできます。
.item {
display: grid;
grid-template-columns: subgrid;
grid-column: span 2;
}
ポイント:
subgridにより、子要素は親の列トラック定義を継承できる- 画像が 1 列、テキストがもう 1 列を占め、それぞれ内容に応じて自動調整される
- Grid Lanes と通常の Grid は相互にネストできる
flow-tolerance を調整する
(08:37)
デフォルト動作です。
.container {
display: grid-lanes;
grid-template-columns: 1fr 1fr;
gap: 10px;
flow-tolerance: normal;
}
許容差をカスタマイズします。
.container {
display: grid-lanes;
grid-template-columns: 1fr 1fr;
gap: 10px;
flow-tolerance: 2.1em;
}
ポイント:
- デフォルト値は
1em - ブラウザは各列の高さを比較し、高さ差が許容範囲内なら DOM 順を優先して埋める
- 許容差が大きいほど視覚順は DOM 順に近くなるが、列の高さの違いは目立ちやすくなる
- Safari Web Inspector は Grid Lanes 専用の Overlay を提供し、列線、要素の順序番号、隙間を表示できる
核心アイデア
-
何を作るか: App 内の画像 masonry レイアウトを JavaScript ライブラリからネイティブ CSS へ移行する なぜ価値があるか: スクリプトサイズを減らし、実行時の高さ計算をなくし、WKWebView 内のスクロールをより滑らかにできる どう始めるか:
@supports (display: grid-lanes)でプログレッシブエンハンスメントを行い、対応ブラウザはネイティブ、非対応ブラウザは旧実装を使う -
何を作るか: コンテンツサイトにレンガ壁型のタイムラインレイアウトを追加する なぜ価値があるか: Grid Lanes の横方向フローモードは、タイムラインや手順の表示に自然に合う どう始めるか:
grid-template-columnsをgrid-template-rowsに置き換え、spanで重要カードを制御する -
何を作るか:
flow-toleranceで既存 masonry のアクセシビリティ問題を修正する なぜ価値があるか: 多くのサードパーティ masonry ライブラリには、DOM 順と視覚順が一致しない欠点がある どう始めるか: Grid Lanes コンテナにflow-tolerance: 1emを追加し、Safari Web Inspector の Overlay で Tab フォーカス経路を確認する -
何を作るか: 複数列にまたがるカード内で
subgridを使い、画像とテキストを揃える なぜ価値があるか: 大きな画像と説明文を組み合わせるカードでは、内部グリッドを外部グリッドに揃えたいことが多い どう始めるか: カードにgrid-column: span 2とgrid-template-columns: subgridを追加し、画像とテキストをそれぞれ 1 列に配置する
関連 Session
- Safari 27 の WebKit 新機能 - Safari 27 の新機能全体を概観する。Grid Lanes はその一部
- 空間ユーザーインターフェイスの設計原則 - 空間インターフェイスの設計原則。レスポンシブレイアウトの考え方とも通じる
- SwiftUI の基礎 - SwiftUI の LazyVGrid と Grid Lanes は同じ種類の問題を解くため、2 つのプラットフォームの実装を比較できる
コメント
GitHub Issues · utterances