ブラウザの基礎(ネットワーキング、レンダリング、キャッシュ)を神話抜きで解説。AI生成フロントエンドでよくあるミスを見抜き、回避するための実践的な知識を提供します。

多くのフロントエンドのバグは「ブラウザの謎の挙動」ではありません。"ブラウザは何でもキャッシュする" や "React はデフォルトで高速" といった中途半端に覚えたルールの結果です。そういうフレーズはもっともらしく聞こえるので、"何と比べて速いのか"、"どんな条件で" と問わずに納得してしまいがちです。
Web はトレードオフで成り立っています。ブラウザはネットワーク遅延、CPU、メモリ、メインスレッド、GPU 作業、ストレージ制限を同時に扱います。概念が曖昧だと、ラップトップでは問題ない UI を出荷してしまい、ミドルレンジのスマホや不安定な Wi‑Fi 上で崩壊することがあります。
現実のバグにつながりやすい一般的な思い込みの例:
AI生成のフロントエンドはこうしたミスを増幅することがあります。モデルは正しく見える React ページを出せても、遅延を体感しませんし、帯域幅のコストも考えません。レンダリングごとに余計な作業を引き起こすことに気づかないことが多いです。不要な大きな依存を追加したり、巨大な JSON を HTML にインラインしたり、同じデータを二度フェッチしてしまったりします。
Koder.ai のようなビブコーディングツールを使う場合は特に注意が必要です:UI を高速に大量生成できる一方で、ブラウザでの隠れたコストが誰にも気づかれないまま積み上がることがあります。
この記事では、日常の仕事でよく出てくる基本に絞ります:ネットワーキング、キャッシュ、レンダリングパイプライン。目的は、ブラウザが何をするか予測できるメンタルモデルを提供し、よくある「速いはず」トラップを避けられるようにすることです。
ブラウザを URL をピクセルに変える工場と考えてください。工程が分かれば、どこで時間を失っているか予想しやすくなります。
ほとんどのページは次の流れに従います:
サーバーは HTML、API レスポンス、アセットとともにキャッシュやセキュリティを制御するヘッダーを返します。ブラウザの仕事はリクエストの前(キャッシュ検索、DNS、接続設定)に始まり、レスポンスの後(パース、レンダリング、スクリプト実行、次回用のストレージ)まで続きます。
多くの混乱は、ブラウザが一度に一つのことしかやらないと想定することから生じます。実際はそうではありません。ネットワークリクエストや画像のデコード、一部のコンポジティングはメインスレッド外で行われます。一方でメインスレッドは「ここをブロックするな」レーンです。ユーザー入力を処理し、大半の JavaScript を実行し、レイアウトやペイントを調整します。メインスレッドが忙しいとクリックが無視されたように感じたり、スクロールがぎこちなくなります。
遅延は主に次の箇所に隠れています:ネットワーク待ち、キャッシュミス、CPU負荷の高い作業(JavaScript、レイアウト、過剰な DOM)、GPU 負荷の高い作業(大きすぎるレイヤやエフェクト)。このメンタルモデルは、AI ツールが見た目は問題ないものを生成しても手触りが遅い理由を考えるときに役立ちます:たいていはどれかの工程で余分な作業を作っているからです。
ページは「実際のコンテンツ」がダウンロードされる前から遅く感じることがあります。ブラウザはまずサーバーに到達しなければなりません。
URL を打つと、ブラウザは通常 DNS(サーバーを見つける)、TCP 接続の確立、TLS のネゴシエーション(暗号化と検証)を行います。特にモバイル回線ではそれぞれが待ち時間を増やします。だから「バンドルは200KBしかない」はまだ遅く感じることがあるのです。
その後ブラウザは HTTP リクエストを送り、レスポンス(ステータスコード、ヘッダー、ボディ)を受け取ります。ヘッダーはキャッシュ、圧縮、コンテンツタイプを制御するため UI に影響します。コンテンツタイプが間違っていると想定通りにパースされませんし、圧縮が無効だとテキスト資産が大きなダウンロードになります。
リダイレクトも時間の無駄になりやすいです。1つ余分なホップは別のリクエストとレスポンス、場合によっては別の接続設定を意味します。ホームページが別の URL にリダイレクトされ、それがさらに別にリダイレクトされる(http→https、次に www、次にロケール)と、重要な CSS や JS を取得する前に複数の待ちが発生します。
サイズは画像だけではありません。HTML、CSS、JS、JSON、SVG は通常圧縮するべきです。加えて JavaScript が何を引き込むかを監視してください。"小さい" JS ファイルでも、すぐに他のリクエスト(チャンク、フォント、サードパーティスクリプト)を引き起こすことがあります。
UI に関係する簡単なチェック項目:
AI 生成のコードは出力を多くのチャンクに分割したり、デフォルトで余分なライブラリを引き込んだりしてこれを悪化させます。ネットワークは "忙しく" 見えるのに各ファイルは小さく、初期起動時間が悪化します。
「キャッシュ」は一つの魔法の箱ではありません。ブラウザは複数の場所からデータを再利用し、それぞれルールが異なります。メモリ上に短時間だけ残るもの(高速だがリロードで消える)もあれば、ディスクに保存されるもの(再起動後も残る)もあります。HTTP キャッシュがそのレスポンスを再利用できるかどうかを決めます。
多くのキャッシュ動作はレスポンスヘッダーによって決まります:
max-age=...: 時間が切れるまでサーバーと連絡せずにレスポンスを再利用する。no-store: メモリにもディスクにも保持しない(機密データ向け)。public: 共有キャッシュ(ブラウザ以外)でもキャッシュしてよい。private: ユーザーのブラウザだけでキャッシュする。no-cache: 名前が紛らわしい。多くの場合「保存はするが再利用前に再検証する」という意味です。ブラウザが再検証するとき、フルダウンロードを避けようとします。サーバーが ETag や Last-Modified を返していれば、ブラウザは "変わったか?" と問い合わせ、サーバーは "Not Modified" で応答できます。その往復は時間を要しますが、フルダウンロードよりは通常安価です。
一般的なミス(とくに AI 生成のセットアップで)は、app.js?cacheBust=1736 のようなランダムなクエリ文字列をビルドごと、あるいはページロードごとに付けてしまうことです。安全に見えますが、キャッシュを台無しにします。安定した URL を安定したコンテンツには使い、バージョン管理されたアセットにはコンテンツハッシュ入りのファイル名を使うのが良いパターンです。
キャッシュバスターが裏目に出る典型は次の通りです:ランダムなクエリパラメータ、変化する JS/CSS に同じファイル名を再利用する、デプロイごとに URL を変更する(内容は変わっていないのに)、開発時にキャッシュを無効にしてそのまま戻し忘れる。
Service Worker はオフラインサポートや即時再訪問で有用ですが、別のキャッシュ層を追加するため管理が必要です。アプリが "更新されない" 場合、古い Service Worker が原因であることが多いです。何をキャッシュし、更新をどう配信するかを明確に説明できるときだけ使いましょう。
バグの「謎」を減らすには、ブラウザがバイトをピクセルに変える仕組みを学んでください。
HTML が到着すると、ブラウザは上から下へパースして DOM(要素の木)を作ります。パース中に CSS、スクリプト、画像、フォントを発見して表示内容が変わることがあります。
CSS は特別です。ブラウザは最終的なスタイルが分かるまで安全に描画できないため、CSS はレンダリングをブロックし得ます。ブラウザは CSSOM(スタイルルール)を構築し、DOM と CSSOM を組み合わせてレンダーツリーを作ります。重要な CSS の遅延は最初のペイントを遅らせます。
スタイルが確定したら主に次のステップが続きます:
画像やフォントがユーザーに「読み込まれた」と感じさせる大きな要因になることが多いです。ヒーロー画像の遅延は Largest Contentful Paint を遅らせます。Web フォントはテキストが見えなくなるか、スタイルスワップでチラつくことがあります。スクリプトはパースをブロックしたり、追加のスタイル再計算を引き起こしたりして最初のペイントを遅らせます。
「アニメーションは無料」という永続的な誤解がありますが、何をアニメートするかによります。width、height、top、left を変更するとしばしばレイアウト→ペイント→コンポジットを引き起こします。transform や opacity をアニメートするとコンポジティングに留まりやすく、はるかに安価です。
現実的な AI 生成の誤りの例は、たくさんのカードに対して background-position を使ったローディングシマーをアニメートし、タイマーで頻繁に DOM を更新しているようなケースです。結果は常時ペイントが発生することです。通常の対処は簡単で:アニメートする要素を減らす、動きは transform/opacity を使う、レイアウトを安定させる、などです。
ネットワークが速くても、ブラウザが JavaScript を実行している間はページが遅く感じられます。バンドルのダウンロードは第一歩に過ぎません。遅延の大きな要因はパースとコンパイル時間、そしてメインスレッドで実行される作業です。
フレームワークは固有のコストを持ちます。React では「レンダリング」は UI がどうあるべきかを計算することです。クライアントサイドアプリは最初にハイドレーション(サーバでレンダリングされた HTML にイベントを紐付けて差分を解消する処理)を行うことが多く、ハイドレーションが重いと見た目は準備できているのにタップがしばらく無視されることがあります。
問題は長いタスクとして現れることが多いです:JavaScript が長時間(50ms 以上など)実行され、ブラウザがその間に画面を更新できない状態です。これが入力の遅延、フレームの落ち、アニメーションのカクつきとして体感されます。
典型的な原因は明白です:
対処はメインスレッドの作業に注目すると明確になります:
チャット駆動のツール(Koder.ai など)で構築する場合は、これらの制約を直接要求すると役立ちます:初期 JS を小さく保つ、マウント時の effect を避ける、最初の画面をシンプルにする、など。
まず症状を言葉で定義します:「初回読み込みが8秒かかる」「スクロールがぎこちない」「更新後にデータが古いまま見える」など。症状ごとに原因が違います。
最初にネットワーク待ちか CPU 消費かを判別します。簡単なチェック:リロード中にページ上で何ができるか観察します。ページが真っ白で何も反応しないならネットワークが大きな要因のことが多いです。ページは出るがクリックが遅い、スクロールがカクつくなら CPU(メインスレッド)が原因である可能性が高いです。
一つのワークフロー:
具体例:AI 生成の React ページが単一の 2MB の JavaScript ファイルと大きなヒーロー画像を出荷しているとします。自分のマシンでは問題なく見えても、スマホでは JS のパースに数秒かかり応答できません。初回表示の JS を削り、ヒーロー画像をリサイズすると、通常はインタラクションまでの時間が明確に短くなります。
測定可能な改善が出たら、後戻りしにくくします。
予算(最大バンドルサイズ、最大画像サイズ)を設定して超えたらビルドを失敗させる。リポジトリに短いパフォーマンスメモを残す:何が遅かったか、何で直したか、何を監視するか。大きな UI 変更や新しい依存が入ったとき(AI がコンポーネントを素早く生成する場合は特に)に再確認する。
AI は動く UI を素早く書けますが、ページを速く信頼できるものにする地味な部分を見落としがちです。ブラウザの基本を知っていれば、完全に出荷される前に問題を早期発見できます。
過剰フェッチはよくあります。AI 生成ページは同じ画面に対して複数のエンドポイントを叩いたり、小さな状態変化で再取得したり、最初の 20 件だけ必要なのに全データを取得したりします。プロンプトは UI を説明することが多く、データ構造に触れないためモデルはギャップを埋めるために余計な呼び出しを追加します。
レンダーブロッキングも頻出します。フォントや大きな CSS、サードパーティスクリプトが head に入れられがちですが、これらはファーストペイントを遅らせます。結果として重要でないリソースを待って白い画面を見続けることになります。
キャッシュのミスは善意から生じることが多いです。AI は「再利用しないほうが安全」に見えるヘッダーやフェッチオプションを付けてしまうことがあります。結果は不要なダウンロード、遅い再訪問、バックエンドの余分な負荷です。
ハイドレーションの不一致は忙しい React 出力でよく出ます。サーバー側でレンダリングしたマークアップとクライアント側がレンダリングするものが一致しないと React が警告を出したり、再レンダリングしたり、イベントの取り付けがおかしくなったりします。これはランダムな値(日付や ID)を初期レンダリングに混ぜたり、クライアント専用の状態に依存する条件を混ぜたりすると起きます。
これらの兆候が見られたら、そのページはパフォーマンスのガードレールなしで組み立てられたと見なしてください:一つの画面に重複したリクエスト、未使用の UI ライブラリで引き込まれた巨大な JS バンドル、不安定な値で再フェッチする effect、重要な CSS より先に読み込まれるフォントやサードパーティ、リクエスト単位ではなくグローバルで無効にされたキャッシュなどです。
Koder.ai のようなツールを使う場合は、生成物を第一稿として扱ってください。ページネーション、明示的なキャッシュルール、最初に何を読み込むかの計画を要求しましょう。
AI が作った React のマーケティングページはスクリーンショットでは完璧に見えても、実際には遅く感じることがあります。典型的な構成はヒーロー、テストimonials、価格表、そして API を叩く「最新情報」ウィジェットです。
症状はよくあるものです:テキストの表示が遅い、フォントが読み込まれてレイアウトがジャンプする、画像の到着でカードが入れ替わる、API コールが複数回走る、デプロイ後にアセットが古いまま残る。どれも神秘的ではなく、ブラウザの基本動作が UI に現れています。
まず二つの視点で確認します。
1つ目は DevTools の Network のウォーターフォールを開くこと。大きな JS バンドルが全てをブロックしていないか、フォントが遅れているか、サイズ指定のない画像がないか、同じエンドポイントへの繰り返し呼び出し(微妙に異なるクエリ文字列で)がないかを探します。
2つ目はリロード中の Performance トレースを記録すること。長時間タスク(メインスレッドをブロックする JavaScript)と Layout Shift(コンテンツ到着後の再配置)に注目します。
このシナリオでは、少ない修正で大半が改善することが多いです:
aspect-ratio)を設定してブラウザがスペースを確保し、レイアウトジャンプを避ける。改善を確認するには派手なツールは不要です。キャッシュ無効でリロードを 3 回、その後キャッシュ有効で 3 回行いウォーターフォールを比較します。テキストが早くレンダリングされ、API 呼び出しが 1 回に減り、レイアウトが安定しているはずです。最後にデプロイ後にハードリフレッシュして、まだ古い CSS や JS が出るか確認します。出るならキャッシュルールとビルドの運用が合っていません。
Koder.ai のようなツールで作った場合も同じループを回してください:1 回ウォーターフォールを調べ、1 つ直して、また検証する。小さな反復で "AI 生成フロントエンド" が "AI による驚き" に変わるのを防げます。
ページが遅い、またはぎこちないと感じたら、フォークロアではなく以下のチェックでほとんどの現実的な問題を説明できます。AI 生成 UI に出やすい問題も含みます。
まずここから:
ページが単に遅いのではなく "ぎこちない" 場合は、動きとメインスレッドの作業に焦点を当てます。レイアウトシフトは通常、サイズ指定のない画像、遅れて読み込まれるフォント、データ到着後にサイズが変わるコンポーネントが原因です。長時間タスクは大量の JavaScript(重いハイドレーション、重いライブラリ、大量ノードのレンダリング)が原因です。
AI にプロンプトを出すときは、実際の制約を示す言葉を使ってください:
Koder.ai を使っているなら、Planning Mode はこれらの制約を書き出す良い場所です。小さな変更で反復し、デプロイ前にスナップショットやロールバックで安全にテストしてください。