「このボタンの色だけ変えてほしい」。既存サイトの改修では、こういう依頼が来ます。

ゼロから作る案件だけでなく、すでに公開されているサイトの一部だけを直す仕事は珍しくありません。直したい見た目は分かる。分からないのは、その変更が他のページにも出るかどうかです。

自分が書いていないCSSに手を入れるとき、先に確かめたいことは2つあります。どこに書けば安全か、そしてその変更がどこまで波及するか

この記事では、CSS設計を一から作り直す話(リファクタリング)はしません。権限も工数も無い前提で、影響範囲を調べ、既存の行を書き換えずに足し、直したあとに確かめるまでを1本の手順としてまとめます。

ここで挙げるのは既存のCSSを確認する方法の一部です。紹介する手順をすべて毎回なぞる必要はありませんし、案件や環境によっては別の調べ方のほうが早いこともあります。そのなかで、私が実際の改修で確度が高いと感じている方法を選んで並べました。

この記事で分かること
  • 他人が書いたCSSで、そのクラスがどこで使われているかを調べる手順
  • クラス名で検索しても見つからないときに、代わりに見る場所
  • 触ってはいけないCSSの見分け方(更新で消えるもの/他に波及するもの)
  • 既存の行を書き換えずに変更を閉じる書き方と、直したあとの確かめ方

既存サイトのCSSは直さずに足す

部分改修で最初に決めておきたいのは、既存のCSSをどう扱うかです。既存の行を書き換えるより、影響範囲を閉じた形で足すほうが安全です

この記事ではリファクタリングも、未使用CSSの削除も扱いません。既存のコードは残したまま、必要な分だけを足して閉じる。この立場に立つと、作業は次の5ステップになります。

  1. どこで使われているかを調べる
    ソースとブラウザの両方を見ます。
  2. 使用箇所の数で直し方を決める
    1ページだけか、複数ページかで手段が変わります。
  3. 触ってよいファイルかを確かめる
    触ってはいけないファイルには目印があります。
  4. 名前を決めて、影響範囲を閉じて書く
    既存の命名に合わせ、変更が届く範囲を限定します。
  5. 直したあとに答え合わせをする
    何を見るかは着手前に決めておきます。

検証環境やステージングがあるなら、まずそこで試します。無い場合でも、あとで元に戻せる形にしてから着手する点は変わりません。

なお、複数のルールがぶつかったときにどちらが勝つかという話は、この記事では扱いません。上書きが効く・効かないの仕組みそのものは CSSの詳細度は「点数の合計」ではない にまとめています。

クラスがどこで使われているかを調べる

調べる場所は2つあります。リポジトリのソースと、ブラウザで表示した実画面です。

ソースを検索するほうが速いのですが、それだけを見ていると取りこぼす可能性があります。ソースに存在しないクラス名が画面に出ていることがあるためです。なぜそうなるのかは次の章で分類します。

ソースをテキスト検索する

まずクラス名の完全一致で検索します。出てこなければ、区切り記号の手前で切って部分一致で検索し直します。

Bash
# 完全一致で探す
grep -rn "card__title" .

# 区切り記号の手前で切って部分一致で探す
grep -rn "card__" .

-r はサブディレクトリを再帰的にたどるオプション、-n は一致した行番号を表示するオプションです。この grep -rnnode_modules/.git/ の中まで走査するので、--exclude-dir で除外しておくと結果が読みやすくなります。

検索対象はCSSファイルだけにしません。HTML・テンプレート・JSファイルまで含めます。クラス名がCSS以外の場所に書かれていることがあるためです。

ブラウザに出力されたHTMLを検索する

ソースで見つからないときは、ブラウザに出力されたHTMLを見ます。Chromeの開発者ツールには、読み込まれた全リソースを横断してテキスト検索する Search パネルがあります。

  1. 開発者ツールを開く
    ページ上で右クリックして「検証」を選びます。
  2. Search パネルを開く
    Cmd+Opt+F(Windowsは Ctrl+Shift+F)で下部に検索欄が出ます。
  3. クラス名を入力して検索する
    正規表現と大文字小文字の区別を指定できます。

ヒットしたリソースと行が一覧で並び、そこから該当ファイルを開けます。ソースでは切れていた文字列が、ブラウザに出力されたHTMLでは見つかることがあります。

ひとつ注意があります。この検索の対象は読み込まれたリソースであり、ネットワークのヘッダやレスポンスは対象外です(Chrome公式ドキュメントに明記があります)。

そのページでの使用数を数える

見つけたあとは、そのページで何箇所使われているかを数えます。開発者ツールのConsoleでは $$() が使えます。

JavaScript
$$('.card__title').length;
$$('[class*="card__"]').length;

1行目はそのクラスの使用数、2行目は card__ を含むクラス名が付いた要素の数です。$$()Array.from(document.querySelectorAll()) と同じ働きをするもので、開発者ツールのConsole限定です。

この方法の利点は、JSがクラスを付けたあとの状態で数えられることにあります。

主要なページを順に開いて、それぞれで同じ2行を実行し、数を記録していきます。この記録が、次の「何ページで使われているか」の判断材料になります。

grepで見つからない3つの理由

「検索したのに1件も出てこない。でも画面には当たっている」。この状態は、文字列がどこで切れたかで3つに分かれます。そして切れた場所によって見る場所が変わってきます

CSS側で文字列が切れている

Sass/SCSSの &__ 記法では、書いたソースの中に完成後のクラス名が存在しません。

SCSS
.card {
  padding: 16px;

  &__title {
    font-size: 20px;
  }
}

これをコンパイルすると、次のCSSが出力されます。

CSS
.card {
  padding: 16px;
}

.card__title {
  font-size: 20px;
}

出力側には .card__title があります。しかしソース側には card__title という連続した文字列がどこにもありません&__title と書かれているだけです。検索が空振りするのはこのためです。

同じことは他の記法でも起きます。

起きること何が起きているか代わりに何を見るか
&__ 記法のネストコンパイル後に親ブロック名と連結される。ソースに完成形の文字列が無いビルド後のCSSを検索する/親ブロック名で検索してファイル内を追う
#{$変数} の補間クラス名の一部が変数(.#{$prefix}-btn変数の定義値を先に確認してから検索する
プレースホルダ %@extendセレクタが別名で合流している出力CSSでセレクタリストを確認する

いずれも解決策は同じで、ソースではなく出力(ビルド後のCSS)を検索することです。ソースを読むのが正しいという普段の判断が、ここでは逆に働きます。

HTML側で実行時に組み立てられている

クラス名がJS・テンプレート・CMSによって実行時に組み立てられる場合も、ソースに完成形の文字列は存在しません。

起きること具体例代わりに何を見るか
JSがクラスを付け外しするel.classList.add('is-active')JSファイルも検索対象に入れる。classList className で先に洗い出す
テンプレートが文字列を連結するclass="btn btn-<?= $type ?>"連結の前半(btn-)で部分一致検索。変数の取りうる値を探す
フレームワークがクラスを束ねるVueの :class、Reactの条件分岐テンプレート式は静的解析で追えない。ブラウザに出力されたHTMLを見る
CMSがクラスを自動付与するページ種別・投稿種別のクラスを関数が出力するソースに文字列が無い。ブラウザに出力されたHTMLを見る
ユーティリティを動的に組み立てるbg-${color}-600実際の出力を見る/safelist の設定ファイルを見る

WordPressの body_class() は、page-id-2single といったクラスを関数側で組み立てて出力します。テンプレートを検索しても、これらの文字列は出てきません。

表の最後にある、ユーティリティクラスを動的に組み立てるケースも同じ性質です。Tailwind CSSでは、クラス名を変数で組み立てるとビルド時の静的解析で検出されないことが公式に説明されています。なお safelist を書く場所はバージョンによって違い、設定ファイルに書く方式と、CSS側に @source inline(…) で書く方式があります。

このケースの解決策は、ソースではなくブラウザに出力されたHTMLを見ることです。前章の Search パネルが使えます。ただし Search パネルが探すのは読み込まれたリソースなので、bg-${color}-600 のようにJSが実行時に組み立てるクラスは、Elements パネルや $$() で確かめます。

ビルドでクラス名が別物になっている

3つ目は、そもそも名前が一致しないケースです。

起きること具体例代わりに何を見るか
CSS Modules.titleCard_title__x7f2a のようなファイル名+ハッシュに変換される(構成による)ハッシュより前の Card_title で検索する
CSS-in-JS生成したスタイルのハッシュからクラス名を作る。人が付けた名前が残らないクラス名ではなくコンポーネント名で追う
クラス名の圧縮.a .b のような短い名前に置き換えられるソースマップを使う/圧縮前の成果物を見る

ここでの前提は、ブラウザで見えている名前とソースの名前は別物だということです。名前で追うのをやめ、コンポーネント単位で追います。

ただしCSS Modulesのように命名規則が残っていれば、ハッシュより前の部分での検索がまだ効きます。

使用箇所の数で直し方が決まる

数える前に、確認しておきたい前提があります。既存のコードに手を入れてよいかどうかは、案件と発注者の方針で決まります。制作会社経由の依頼では「既存のソース部分は触らないでほしい」と指定されることもあります。この確認が取れていないうちは、使用箇所が1ページであっても既存の行には触りません。

こちらの判断で修正してよいと確認が取れている場合は、数えた結果がそのまま直し方の判断材料になります。1ページに閉じているかどうかで、既存の行に触れる余地が変わります

使用箇所直し方
そのページだけ既存のルールに宣言を足す選択肢も入る。ファイルの出所と、そのルールが他ページに出ないことを先に確認する
2ページ〜数ページ既存の行は触らず、対象だけに当たるクラスまたは親を足して分岐させる
ほぼ全ページ(共通パーツ)既存の行は書き換えない。新しいルールを足して閉じる

1ページに閉じている場合でも、既存の行を残したまま足す選択はいつでも取れます。迷ったときは足す側に倒しておくほうが、切り戻しの手間は小さくなります。

数え方には限界が2つあります。着手前に把握しておきます。

  • 主要ページを回っただけでは全ページを網羅できない。数えきれないときは多いほうに倒す
  • JSが後から付けるクラスは、その画面の状態を再現しないと数に出ない

触ってはいけないCSSは2種類ある

触ってはいけないと言われるCSSには、理由が2つあります。(a) 更新で上書きされて消えるもの。(b) 消えはしないが、他に波及するもの。

そして理由が違うので、対処も正反対になります。(a) は別の場所に書く。(b) はスコープを足して分岐させる。まとめて「触るな」で済ませると、どちらの対処もできなくなります。

更新で上書きされて消えるもの

こちらはパスとファイル形式で機械的に判定できます。中身を読んで悩む必要がありません。次のいずれかに当てはまるファイルは、直接編集しない側に置きます。

  • node_modules/ vendor/ bower_components/ の中にある
  • CMSの配布物の中にある(WordPressなら親テーマや wp-content/plugins/ の中)
  • ビルドの出力先にある(dist/ build/ public/css/
  • ファイル名が .min.css
  • 先頭にライセンスコメント /*! … */ がある
  • 冒頭に「編集しないでください」の注記がある

理由は共通していて、これらは次回の更新でファイルごと差し替わるからです。直した内容が消えるだけなら、まだ気づけます。問題は、消えたことに誰も気づかないまま運用が続くことにあります。

対処は「別の場所に書く」。その別の場所をどう選ぶかは、後述の「どのファイルに書くかで閉じる」で扱います。

消えないが他に波及するもの

こちらは性質が逆で、変更が成功してしまうのが怖いケースです。担当ページは意図どおりに直る。同時に、確認していないページも変わります。

目印具体例対処
共通ファイルに書かれているcommon.css style.css の上部・foundation/ layout/ 配下既存の行を書き換えず、別のセレクタで上書きする
共通パーツのクラス.header .footer .btn .section-title修飾クラスを足して分岐させる
型セレクタ・全称セレクタp { } a { } * { }サイト全体に効く。書き換えず、対象を限定した新規ルールを足す
リセットCSS・正規化CSSreset.css normalize.css触らない。必要な箇所だけ個別に打ち消す
js- プレフィックス・data-* が付いているjs-modal-triggerCSSではなくJSが掴んでいる。クラス名を変えない

表の最後の行は見た目に関係がないので見落とされがちですが、実害が大きい部分です。

HTML
<button class="js-modal-trigger btn">申し込む</button>
JavaScript
const trigger = document.querySelector('.js-modal-trigger');
trigger.addEventListener('click', openModal);

この js-modal-trigger を、命名が気に入らないという理由で btn-modal に変えたとします。すると querySelectornull を返し、次の行でエラーが出てモーダルが開かなくなります。CSSを直したつもりが、JSを壊しています。

見た目の理由でクラス名を改名しない。これは触ってはいけないものの中でも、特に単純で守りやすいルールです。

足すクラスは既存の命名に合わせる

新しくクラスを足すときは、自分の流儀を持ち込みません

きれいに書くことと、次に触る人が読めることは別です。サイト内に2つの流儀が混在すると、次に入る人は2つとも読まされます。既存が自分の好みでない書き方でも、揃っているほうが読む負担は小さくなります。

何を見て流派を判定するか

既存のコードから読み取れる材料は6つあります。順に見ていけば、規則の有無とその形が分かります。

見るもの観察のポイント読み取れること
区切り記号__ -- があるか/- だけか/キャメルケースか__ -- があればBEM系の可能性が高い
プレフィックスl- c- p- u- / is- / js-層や役割の分け方。js- はJSが掴んでいる印
ディレクトリ構成foundation/ layout/ object/ があるか/components/ か/1ファイルか設計思想がそのまま出る。1枚のCSSしか無いなら設計は無いと判断してよい
クラスの粒度1要素に1クラスか、mt-20 text-center のような単機能クラスが並ぶかユーティリティ主体かコンポーネント主体か
状態クラスの付け方is-open / active / open / --open新しく状態を足すときの形が決まる
既存の詳細度の高さIDセレクタ・深いネスト・!important の多さ追記時にどこまで強く書く必要があるかの目安

プレフィックスの行にある js- は、前章で見たとおりJSが掴んでいる印です。この現場がCSSとJSでクラスを使い分けているかどうかも、ここで分かります。

判定結果ごとの命名の決め方

判定できたら、次の対応で決めます。

既存の状態新しく足すクラスの方針
一貫した規則があるその規則に従う。既存のブロック名を親にして要素を足す
規則はあるが部分的に崩れている一番多く使われている形に合わせる
規則が無い今回の改修範囲だけに通用する接頭辞を1つ決めて足す
ユーティリティ主体既存のユーティリティで組めないか先に確認。無ければ既存の形式に沿って1つ足す

2行目の「一番多く使われている形」は、最新の形でも、正しい形でもありません。多数派です。次に触る人が最初に目にする形に合わせるほうが、読み解く手間が減ります。

3行目のように規則が無い場合でも、全体の設計は始めません。今回の改修範囲で閉じる接頭辞を1つ用意すれば足ります。

影響範囲を閉じる書き方

閉じ方は3系統あります。セレクタで閉じる、ファイルと読み込みで閉じる、CSSの言語機能で閉じる。仕組みが違うので、効き方も副作用も違います。

セレクタで閉じる

最も安全なのは、既存のルールを変えず、対象だけに当たる新しいルールを足す方法です。

CSS
/* 変更前: 既存のルール。サイト全体のボタンに当たっている */
.btn {
  background-color: #2f6f7e;
}
CSS
/* 変更後: 既存の行はそのまま。対象のボタンにだけ .is-cta を足す */
.btn.is-cta {
  background-color: #c0552f;
}

.btn の行には手を触れていません。.is-cta を付けたボタンだけが変わり、他の利用箇所には何も起きません。

手段は他にもあります。それぞれ効く条件が違います。

手段書き方効く条件・副作用
新しいクラスを足す.btn.is-cta { … }既存の利用箇所に影響しない。HTMLを触れることが条件
ページ固有のクラスを親に足す.page-contact .btn { … }body 等にページ用のクラスを用意できる場合に使える
CMSが自動で付ける識別子を親に使う.page-id-2 .btn { … }HTMLを触らずにページ限定にできる。ID番号は環境の移行で変わりうる。移行の可能性がある案件ではこの手段に依存しない
既存の親を1段足す.contact-form .btn { … }手軽だが、その親が他ページにも出るなら閉じていない

最後の「既存の親を1段足す」は、その親が他ページに出ないことを先に確認してから使います。親が他ページにもあると、閉じたつもりで閉じていない状態になります。

なお、親を足すとセレクタの詳細度は1段上がります。上がった結果として既存のルールに勝てるのかどうかは、詳細度の数え方で決まります。その数え方は以下の記事で解説しています。

どのファイルに書くかで閉じる

書く場所そのものでも範囲を制御できます。選択肢は5つあります。

書く場所向いている場面注意
既存ファイルの該当セクションに追記既存の規則がしっかりしていて、変更が既存パーツの延長のときそのファイルが更新で上書きされる出所でないことが前提
既存ファイルの末尾に追記出現順で勝たせたいときどこに何を足したか分からなくなる。コメントで改修日と範囲を書く
改修用CSSを新規に追加して最後に読み込む既存ファイルを触りたくない/触れないとき今回の変更を1ファイルに固められる。切り戻しがファイルの削除で済む
そのページでだけ読み込む変更が1ページに閉じているとき他ページに物理的に届かない。読み込み制御ができるサイトに限る
管理画面のCSS欄に書く少量・緊急・自分以外も触る運用のときバージョン管理の外に出る。恒久対応には向かない

今回の変更だけを1ファイルに固めて最後に読み込むと、切り戻しがファイルの削除だけで済みます。何を変えたかが1箇所にまとまるので、次に触る人にも伝わります。

そのファイルの冒頭に、次の4項目をコメントで残しておくと、後から見た人が判断しやすくなります。

CSS
/* ---------------------------------------------
 * 改修用CSS(2026-08-13)
 * 依頼内容: お問い合わせページの申し込みボタンの色を変更
 * 変更範囲: .btn.is-cta(お問い合わせページのみ)
 * 切り戻し: このファイルの読み込みを外す
 * --------------------------------------------- */

残すのは改修日・依頼内容・変更範囲・切り戻し方法の4つです。

表の最後にある管理画面のCSS欄は、その場で反映できる手軽さがある一方で、バージョン管理の外に置かれます。差分が追えないので、緊急対応の一時置き場として使い、落ち着いたらファイルに移すほうが後が楽になります。

@scope で範囲を区切る

CSSには、範囲そのものを区切る @scope があります。スコープの上限と下限を指定できるのが特徴です。

CSS
@scope (.article-body) to (figure) {
  img {
    border: 1px solid #ddd;
  }
}

これは「.article-body の中の img に適用する。ただし figure の中は除く」という指定です。上限と下限で挟んだ形をドーナツスコープと呼びます。ブロック内の素のセレクタは詳細度を上げずに書けます。

ただし使える案件は限られます。

  • Baseline Newly available に入ったのは2025年12月。Firefoxの対応が最後発
  • 古い環境の表示を保証する案件では使えない

@scope を選べない案件では、上限にあたる部分だけを、対象を囲む親セレクタで代用します。代用できるのは「この中だけに効かせる」という上限までで、figure の中は除くといった下限は親セレクタでは表現できません。除きたい部分は、個別に打ち消すルールを足して対応します。また親を1段足した分、詳細度は上がります。

@layer は影響範囲を閉じる機能ではない

@layer はここまでの3系統のどれでもなく、レイヤーを分けて優先順位を整理する仕組みです。範囲を閉じる仕組みではありません

ここを取り違えると、期待と逆の結果になります。「既存CSSはそのままにして、改修分だけをレイヤーに入れる」という使い方を考えたとします。しかしレイヤーに入れていないスタイルは、すべてのレイヤーより優先されます。既存CSSはレイヤーの外にあるので、レイヤーに入れた改修分のほうが弱くなります。!important が付く場合はこの関係が変わりますが、ここでは通常の宣言を前提とします。

影響範囲を閉じたいときは、この章で先に挙げたセレクタとファイルの方法を使います。

直したあとの答え合わせ

答え合わせで大事なのは順番です。確認するページの一覧と、変更前の画面のスクリーンショットを先に用意しておく。着手したあとでは、変更前の状態はもう残せません。

手段は3つあります。

手段やること適する場面
目視チェックリスト変更前に見る対象の一覧を作り、変更後に同じ順で回るページ数が少ない小規模改修。ツール不要でここが基本
変更前後のスクリーンショット比較変更前に主要ページを撮っておき、変更後と並べる目視だけでは気づけない数pxのずれを拾える
VRT(ビジュアルリグレッションテスト)スクリーンショットの差分を自動で検出する継続保守案件・ページ数が多い場合

小規模な部分改修なら、1つ目のチェックリストで足ります。作り方は単純で、「見るページ × 見る幅(SP/PC)」の一覧を変更前に書き出し、変更後に同じ順で回るだけです。調査のときに開いた主要ページがそのまま候補になります。

VRTは継続保守案件やページ数が多い場合の選択肢です。単発の部分改修に導入するには準備の手間が大きいので、必要になった時点で検討すれば足ります。

まとめ

  • 部分改修では既存の行を書き換えない。影響範囲を閉じた形で足す
  • クラス名で見つからないのは、CSS側・HTML側・ビルドのどこかで文字列が切れているから。切れた場所によって代わりに見る場所が変わる
  • 触ってはいけない理由は2種類。更新で消えるものは別の場所に書き、他に波及するものはスコープを足して分岐させる
  • 変更前にチェックリストとスクリーンショットを用意する。着手後には撮れない

他人が書いたCSSは、読み解いてから触るまでの距離が長く感じられます。調べる場所と判断の順番が決まっていれば、その距離は短くなります。次の改修では、手を動かす前に使用箇所を数えるところから始めてみてください。

関連記事

  • 上書きが効かないときに、どこで負けているかを見分ける
  • 新規案件で自分が設計を決められる場合の書き方
  • 引き継いだサイトを、環境側から見分ける