公開・運用公開 約10分

更新したCSSが反映されないとき:配信された本文と304を照合する

CSSを保存しても古い表示のままなら、再読み込みを繰り返す前に配信内容を調べます。ローカルの再検証サーバーを使い、URL・ETag・応答本文から、キャッシュと更新漏れを切り分ける練習です。

この記事の目次
  1. 調べる順番は、URL、本文、適用された値
  2. 304は、サーバーが変更なしと答えた結果
  3. 内容が変わればETagも変わる練習環境を作る
  4. 灰色、変更なし、青色の三つを記録する
  5. 再読み込みを繰り返しても直らない二つの場面
  6. 本文の目印を変えて、原因の分岐を確かめる

CSSの色を変えて保存したのに、公開ページは以前の色のまま。更新したCSSが反映されないとき、まず確かめたいのは「ブラウザーがどのURLから、どの内容を得たか」です。キャッシュを消して見た目が変わっただけでは、配信の仕組みまで直ったとは判断できません。

HTMLと外部CSSの読み込みが分かる人向けに、架空の写真室の見出しを使います。Node.js 24系と、Networkパネルを使えるブラウザーを用意してください。教材は端末内だけで動かし、実際のホスティング設定や公開中のサイトは変更しません。

調べる順番は、URL、本文、適用された値

最初に開発者ツールのNetworkを開き、ページを再読み込みします。CSSの通信を選び、HeadersのRequest URLとResponseの本文を見ます。Chrome DevToolsの公式資料で、それぞれの確認場所を調べられます。名称はブラウザーや表示言語で異なります。

観察した結果 次に調べる場所
CSSのURLが予定と違う HTMLのlink、公開先の階層、古いHTMLの配信
URLは合うが本文に変更がない 保存先、ビルド結果、配信先や途中のキャッシュ
本文に変更があるが見た目が違う 要素のクラス、適用条件、別のCSSによる上書き

ファイル名だけでは、同名のCSSを別の階層から読んでいることを見落とします。URLはホスト名とパスまで照合します。相対パスの確認は最初の行、CSSの適用元を調べる記事は最後の行に進んだときに使えます。

応答本文には、今回変えた値を目印にします。今回ならh1のcolorが#174ea6かどうかです。状態コード200だけを合格条件にすると、「古いファイルを正常に受け取った」状態も通してしまいます。

304は、サーバーが変更なしと答えた結果

HTTPキャッシュは、受け取った応答を保存して再利用する仕組みです。保存分を再利用する前に、まだ同じ内容かを問い合わせる操作を再検証と呼びます。ETagはサーバーが内容の版を識別するために付ける値で、ブラウザーはIf-None-Matchで以前の値を送れます。

サーバーが同じ版と判断すれば304 Not Modifiedを返し、ブラウザーは保存済みの本文を使います。304自体に新しいCSS本文はありません。版が変わっていれば、今回の練習では200と新しい本文を返します。MDNのHTTPキャッシュの説明で、この往復を確認できます。

Cache-Control: no-cacheは、保存を禁止する名前ではありません。再利用前の検証を求める指定です。no-storeは保存をさせない指定で、両者は用途が違います。また、メモリーやディスクから再利用したという表示は、サーバーとの再検証で304を受けたこととは分けて記録します。

内容が変わればETagも変わる練習環境を作る

空の練習フォルダに、次の内容でstyle.cssを保存します。最初は濃い灰色です。

body { margin: 2rem; font-family: sans-serif; line-height: 1.8; }
h1 { color: #333333; }

同じフォルダへ次をserver.mjsとして保存します。CSSの本文から識別値を作り、同じ値が届いた場合だけ304を返す小さなサーバーです。公開用のサーバーではなく、再検証の条件を観察するための教材です。

import { createServer } from 'node:http';
import { readFile } from 'node:fs/promises';
import { createHash } from 'node:crypto';

const html = `<!doctype html><html lang="ja"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>写真室|キャッシュの練習</title>
<link rel="stylesheet" href="/style.css">
</head><body><h1>写真室の案内</h1>
<p>架空の練習ページです。見出しの色を変更します。</p>
</body></html>`;

createServer(async (request, response) => {
  try {
    if (request.url === '/') {
      response.writeHead(200, {
        'Content-Type': 'text/html; charset=utf-8',
        'Cache-Control': 'no-store'
      });
      response.end(html);
    } else if (request.url === '/style.css') {
      const css = await readFile(new URL('./style.css', import.meta.url));
      const etag = '"' + createHash('sha256').update(css).digest('hex') + '"';
      const unchanged = request.headers['if-none-match'] === etag;
      response.writeHead(unchanged ? 304 : 200, {
        'Content-Type': 'text/css; charset=utf-8',
        'Cache-Control': 'no-cache',
        ETag: etag
      });
      response.end(unchanged ? undefined : css);
    } else {
      response.writeHead(404, { 'Cache-Control': 'no-store' });
      response.end('Not found');
    }
  } catch {
    response.writeHead(500, { 'Cache-Control': 'no-store' });
    response.end('Practice file could not be read');
  }
}).listen(8766, '127.0.0.1', () => {
  console.log('http://127.0.0.1:8766/');
});

ターミナルでnode server.mjsを実行し、表示されたローカルURLを開きます。終了はCtrl+Cです。ポートが使用中というエラーなら、別のアプリを勝手に止めず、末尾の8766を空いている番号へ変えます。HTTP応答を組み立てるAPIはNode.js 24の公式資料を参照できます。

この教材のETag照合は、一つの識別値がそのまま返る通常のブラウザー操作向けです。条件付きリクエストの全構文を実装したものではありません。依存ライブラリの導入や実運用の設定より、本文と版が対応することを観察します。

灰色、変更なし、青色の三つを記録する

NetworkのDisable cacheを外した状態で開き、style.cssのETagを控えます。続けて、ファイルを変更せず通常の再読み込みをします。標準的な再検証ではIf-None-Matchに控えた値が送られ、304が返ります。開発者ツールが再利用後の内容を見せる場合もあるので、本文欄が空かどうかだけで判断しません。

次にstyle.cssの#333333を#174ea6へ変えて保存し、再読み込みします。ETagが変わり、200の応答本文に#174ea6が入り、見出しも青くなれば対応が取れています。ブラウザーの操作や設定により条件なしで取り直した場合は200になります。304を出すためだけに設定を変え続けず、送った条件と結果を一組で読みます。

段階 リクエストの条件 期待する応答と内容
初めて開く 保存済みの識別値なし 200、灰色のCSS、識別値A
変更せず再検証 If-None-MatchがA 304、保存済みの灰色を利用
色を変更して再検証 If-None-MatchがA 200、青色のCSS、別の識別値B

再読み込みを繰り返しても直らない二つの場面

一つ目は、キャッシュを疑っているのに実は違うCSSを編集している場合です。Disable cacheを有効にして取り直しても、応答本文に新しい色がありません。修正はRequest URLが指す配信物を特定し、その編集元を直して必要なビルドと配信をやり直すことです。再確認では、同じURLの本文に新しい値が入ったかを見ます。

二つ目は、青色のCSSが届いているのに、後から読んだ別の規則で灰色へ戻される場合です。再検証やキャッシュ削除を繰り返しても、CSS同士の優先関係は直りません。対象のh1を選び、計算済みのcolorから適用元へ戻って、その規則を修正します。本文が青、計算済みの値も青、という二段階で確認してください。

Disable cacheは、DevToolsを開いている間のブラウザーキャッシュを調べるために使います。CDNなど配信途中の保存内容を一括削除する機能ではありません。Service Workerが応答している表示がある場合も、通常のHTTPキャッシュだけの教材から外れるので、その配信経路を別に調べます。

本文の目印を変えて、原因の分岐を確かめる

15〜20分を目安に、青への変更を終えた後、見出しのfont-size: 28pxをCSSへ追加します。確認条件は、応答本文に28pxがある、ETagが前回から変わる、計算済みの文字サイズが28pxになる、の三つです。変更なしの再検証では、その版の保存内容を使えることも確認します。

URLを変える配信方式を採る場合も、HTMLが新しいURLを参照していなければ更新は届きません。まず今回の三条件でどこまで一致したかを記録し、恒久的なキャッシュ方針は配信環境に合わせて決めます。更新後の確認範囲の記事や公開・運用の無料レッスンの確認表には、「表示できた」に加えて、配信本文のどの値を見たかを残してください。

TRY A LESSON

記事の内容を、課題で確かめる

公開・運用の手順を考える練習 →

公開・リリースの学習内容 →

記事についてのお問い合わせ

記載内容へのご質問や訂正のご連絡は、hello@junkbranding.comまでお願いします。

← 記事一覧に戻る