コンテンツにスキップ

ナビゲーション

従来のフルページ遷移には、ドキュメントが切り替わるときの白い点滅と、操作の流れを 止める待ち時間がありました。シングルページアプリケーションはこの 2 つを避けましたが、 いまでは唯一の選択肢ではありません。

ビュートランジションと Speculation Rules は、ハンドラやレスポンスを変えずに、 ブラウザ側でこの問題を軽減します。未対応のブラウザでも、通常のページ遷移として そのまま動きます。

両方のページが読み込むスタイルシートに 1 行足します。

@view-transition { navigation: auto }

同一オリジンの遷移が、切り替わりではなくクロスフェードになります。設定はこれで 全部で、費用は宣言 1 つです。

この規則はコンポーネントのスコープ付き <head> ブロックをそのまま通り抜けます —— スコープすべきセレクタを持たない at-rule だからです —— が、本来の置き場は共有の スタイルシートかドキュメントシェルです。遷移は 1 つのコンポーネントではなくサイトの 性質だからです。

要素に名前を与えると、フェードではなく移動します。両方のページで概念的に同じもの —— 一覧のサムネイルと詳細ページのヘッダ画像 —— に同じ view-transition-name を 与えてください。

<head>
<style>
.hero { view-transition-name: task-hero }
@media (prefers-reduced-motion: reduce) {
:global(::view-transition-group(*)) { animation: none }
}
</style>
</head>

view-transition-name は、遷移が始まる時点でドキュメント内で一意でなければ なりません。リストではつまり、名前はすべての行ではなく遷移先になる項目のもの です。クリックされた行に付けるか、行ごとに別の名前を付けてください。

ドキュメント間のビュートランジションはまだ全エンジンにはありません。ない環境では 遷移はこれまでどおり起きます。早い段階で入れて安全なのはそのためです。

すでに終わっているナビゲーション

Section titled “すでに終わっているナビゲーション”

Speculation Rules は、クリックの前にページを取得する —— あるいは完全に描画する —— ようブラウザに伝えます。置き場はドキュメントシェルで、JSON はそのまま書けます。

package templates
export component Document(children: html?): html {
<!doctype html>
<html lang="ja"><head>
<meta charset="utf-8">
<title>My App</title>
<script type="speculationrules">
{"prerender": [{"where": {"href_matches": "/tasks/*"}, "eagerness": "moderate"}]}
</script>
</head>
<body><slot /></body></html>
}

スクリプト内の中括弧は、テンプレートの挿入として読めない限りリテラルです。ルールの ブロックがそう読まれることはありません。読まれてしまう例は ブラウザ標準の部品にあります。

インラインスクリプト自体を避ける手もあります。レスポンスヘッダでルールを指し示す やり方で、厳しい script-src ポリシーが好むのもこちらです。

Speculation-Rules: "/speculation-rules"

このルートは application/speculationrules+json で答える必要があるため、 public/ に置いたファイル(メディアタイプが拡張子から決まります)ではなく、小さな ハンドラになります。

eagerness 発火 用途
conservative ポインタ/タッチのダウン 生成コストの高いもの
moderate 200ms 程度のホバー 普通の詳細ページ
eager ルールを見つけた時点 次に来る可能性が高い、小さく既知の集合

prerender の代わりに prefetch を使うと、描画せずにドキュメントだけ取得します。 安く、弱く、大きなサイトの既定として妥当です。

href_matches のパターンを広げる前に、あと 2 つ知っておく価値があります。

  • 訪問されなかった prerender も、サーバーの描画 1 回分を消費しています。すべてでは なく、読み手が実際に次へ進むルートに合わせてください。
  • サーバー側の描画を訪問として数える計測は過大になります。document.prerenderingprerenderingchange イベントで、クライアント側の計測を activation まで待たせら れます。

Speculation Rules は今日のところ Chromium の機能です。他ではブロックが無視されます。

フラグメントの swap は遷移なしに領域を差し替えます。URL は変わらず、履歴も増えず、 戻るボタンが返る先もありません。それは扱う状態しだいで、まさに正しいか、静かに 間違っているかのどちらかです。

その状態が 選ぶのは 理由
共有・ブックマーク・再訪の対象になる 遷移 それを運べるのは URL だけ
読み手が 10 回作り直す絞り込み swap 履歴 10 件は、戻るボタンにとって 10 個の誤答
読み手が離脱しうるフローの一段 遷移 離脱できることが要件
一覧の隣の詳細パネル swap、リンク可能なら URL にも反映 両方の性質が欲しい

クラシックな答えが正しいことは多くあります。普通に送信する絞り込みフォームは、 共有できる URL と、機能する戻るボタンと、正しい空状態を無料でくれます。その代償の 往復 1 回は、prerender がすでに払い終えているかもしれません。

swap が必要な場合でも、URL の管理は自分の手に残ります。history.pushState か、 ドキュメントシェルが読み込んでいる swap ライブラリの対応する属性です。フレーム ワークはここに関与しません —— マークアップとステータスで答えるだけで、フラグメントの レスポンスには URL を説明するものが何もありません。

POST に 303 See OtherLocation で答える形は書き込みの正解であり続けますし、 ここまでの話とよく噛み合います。リダイレクト先は普通の GET なので、prerender できて、トランジションの対象にでき、再送信なしに再訪できます。

読み手をどこへ着地させるかは実際の判断です。いま編集した行のフラグメント識別子を 付けて一覧へ戻せば、スクロール復元のコードなしに元の位置が保たれます。