操作して学ぶ

URLを入力してから、画面が表示されるまで

エンジニア面接の定番「ブラウザにURLを打つと何が起きますか?」。 その答えを、HSTS確認からLCPまでの11ステップとして、 目安の経過時間つきでステップ実行できるようにしました。 各ステップの「深掘り」から、裏側の仕組みを解説する記事へ進めます。

0ms経過 ほぼ0ms約0.3〜1s
準備接続往復描画
1/11 準備1ms未満

URLの解釈とHSTS確認

アドレスバーの入力がURLか検索語かを判定し、スキームを補完します。HSTSプリロードリストに載るドメインなら、最初の1回からHTTPSを強制します。

  • 入力文字列をURLとして解釈できなければ既定の検索エンジンへ
  • スキーム省略時は https を補完(HSTS登録済みならHTTPアクセス自体が発生しない)
  • 国際化ドメインは Punycode へ正規化される

左右の矢印キーでも操作できます。時間は東京→東京・初回アクセスの目安。

全ステップの詳解

上のステップ実行と同じ内容を、通して読める形で並べています。

01 URLの解釈とHSTS確認1ms未満

アドレスバーの入力がURLか検索語かを判定し、スキームを補完します。HSTSプリロードリストに載るドメインなら、最初の1回からHTTPSを強制します。

  • 入力文字列をURLとして解釈できなければ既定の検索エンジンへ
  • スキーム省略時は https を補完(HSTS登録済みならHTTPアクセス自体が発生しない)
  • 国際化ドメインは Punycode へ正規化される

02 キャッシュとService Workerの確認0〜1ms

ネットワークへ出る前に、メモリキャッシュ→ディスクキャッシュ→Service Worker の順で手元の資産を確認します。新鮮なキャッシュがあれば、以降のステップは丸ごとスキップされます。

  • fresh なキャッシュ命中なら 0 RTT で描画へ直行(最速のリクエストは「しないリクエスト」)
  • 期限切れでも ETag/Last-Modified があれば条件付きリクエストで 304 を狙う
  • Service Worker の fetch ハンドラが登録済みならオフライン応答も可能

HTTPキャッシュの仕組みブラウザキャッシュの階層Service Worker

03 DNS解決 — 名前をIPアドレスへキャッシュ命中 約1ms/フル解決 20〜120ms

ドメイン名をIPアドレスへ変換します。OSやフルリゾルバのキャッシュに無ければ、ルート→TLD→権威サーバーと反復問い合わせが走ります。

  • スタブリゾルバ→OSキャッシュ→フルリゾルバ(ISP/パブリックDNS)→ルート→TLD→権威の順
  • 各段がTTLに従ってキャッシュするため、人気ドメインはほぼ即答
  • DoH/DoT を使えば問い合わせ自体が暗号化される

DNSの基本DNS解決の内部動作DoH/DoT

04 TCP 3ウェイハンドシェイク1 RTT ≈ 10ms

SYN → SYN-ACK → ACK の往復で、信頼できるバイトストリームの土台を作ります。ここで初めてサーバーと「会話の回線」がつながります。

  • シーケンス番号の初期化とMSS(最大セグメントサイズ)の交渉
  • RTT(往復遅延)がそのままコストになる。東京→東京なら数ms、東京→US西海岸なら約100ms
  • HTTP/3(QUIC)はUDP上でこの往復をTLSと統合し、接続確立を1 RTTに圧縮する

TCPとUDPQUICの内部

05 TLS 1.3ハンドシェイク1 RTT ≈ 10ms(再開時は0-RTTも)

ClientHello に鍵共有材料を同梱し、1往復で暗号化通信を確立します。サーバー証明書のチェーンを検証し、相手が本物であることを確かめます。

  • TLS 1.3 は key_share の同梱で 1 RTT 確立(TLS 1.2 は 2 RTT だった)
  • 証明書チェーン(サーバー証明書→中間CA→ルートCA)を検証
  • セッション再開なら 0-RTT でアプリデータを初手から送ることも可能(リプレイ注意)

TLS 1.3ハンドシェイクの内部セッション再開と0-RTTPKIと証明書チェーン

06 HTTPリクエスト送信片道 ≈ 5ms

メソッド・パス・ヘッダー(Cookie、User-Agent、Accept系)をようやく送出します。ここまでの約40msは、この1通を安全に届けるための準備でした。

  • HTTP/2 なら1本の接続上に複数リクエストを多重化できる
  • ヘッダーは HPACK(HTTP/2)/ QPACK(HTTP/3)で圧縮される
  • Cookieが肥大していると毎リクエストに乗って帯域を食う

HTTP/1.1→2→3の進化HPACKヘッダー圧縮

07 サーバー処理10〜100ms(アプリ次第で桁が動く)

CDNエッジやロードバランサを経てアプリケーションへ。DBクエリを実行し、HTMLやJSONを組み立てます。旅全体で最も変動が大きい区間です。

  • 典型経路: CDNエッジ → LB → リバースプロキシ → アプリ → DB → 応答組み立て
  • 遅いSQL・N+1問題・外部API待ちなど、体感速度の主戦場はここ
  • CDNで静的資産やページ自体をエッジ配信できれば、この区間を丸ごと短絡できる

CDNの仕組みデータベースの基礎運用・可観測性

08 レスポンス転送とスロースタート50KBのHTMLで20ms前後

HTMLが流れてきます。ただしTCPの輻輳ウィンドウは小さく始まるため、初回は数RTTかけて徐々に加速します。大きな初期HTMLはここで損をします。

  • スロースタート: 輻輳ウィンドウがRTTごとに倍々で成長(初期はおよそ10セグメント≈14KB)
  • 14KBに収まる「クリティカルなHTML」は1往復で届く——初期表示最適化の古典的な根拠
  • gzip/brotli 圧縮で転送バイトを数分の1に削減

輻輳制御の系譜Content-Encodingと圧縮

09 HTMLパースとサブリソース発見数十ms〜

届いたそばからHTMLを逐次パースしてDOMを組み立てます。同時にプリロードスキャナが先読みし、CSS・JS・画像の取得を並列で開始します。

  • パースは逐次的——全部届くのを待たずにDOM構築が始まる
  • プリロードスキャナが本パーサより先に走り、リソース取得を前倒しする
  • 同期スクリプトはパーサをブロックする。defer/async/type=module で回避

HTMLパーサとツリー構築クリティカルレンダリングパス

10 スタイル計算 → レイアウト → 描画数十ms

DOMとCSSOMを合成してレンダーツリーを作り、レイアウト(配置計算)→ペイント(ラスタライズ)→コンポジット(合成)と流れて、ついに画素になります。

  • レイアウトは要素の幾何を計算、ペイントは描画命令化、コンポジタがGPUで合成
  • JSがスタイルを読み書きするとレイアウトの再計算(reflow)が走り得る
  • transform/opacity だけのアニメはコンポジタ単独で動くので滑らか

ブラウザレンダリングの仕組み画像デコードと描画

11 最初の描画からLCPへ合計 0.3〜1秒

FCP(最初の描画)を経て、主要コンテンツが表示されるLCPへ。ここまでが「1秒の旅」です。フォント・画像・JSの読み込み戦略がこの数百msを左右します。

  • FCP=何かが最初に描画された瞬間、LCP=最大要素が表示された瞬間
  • Webフォントの読込戦略(font-display)や画像の優先度がLCPを動かす
  • 2回目以降の遷移は bfcache や prerender でほぼ0秒にできる

Core Web Vitalsの内部bfcacheの仕組みプリレンダリング

時間はすべて「東京のユーザーが東京リージョンのHTTPSサイトへ初回アクセス(RTT約10ms)」という想定の目安です。 RTTが100msの海外サーバーなら接続系のステップは約10倍に、キャッシュ命中なら多くのステップが消えます。 続きは ネットワーク Web技術 の各記事へ。