2026年7月23日
2026年7月23日
WordPressのCSSカスタムプロパティ(変数)で色を動的に切り替える方法
WordPressで「管理画面で選んだ色をサイト全体に反映する」「セクションごとにアクセントカラーを変える」「ボタン一つで配色を切り替える」といった動的な色の変更をするなら、色をCSSカスタムプロパティ(CSS変数)にまとめ、値だけを差し替える設計にするのが扱いやすい方法です。この記事では、theme.json が自動で作る色の変数の仕組み、テーマ独自の色変数の設計、設定値からPHPで変数を出力する方法、ブロックテーマでパレットそのものを動的に変える方法、JavaScriptでの切り替え、アクセシビリティ上の注意までを説明します。
カスタムプロパティの基本的な書き方そのものではなく、「WordPressの中で色を動的に変える」ことに焦点を当てています。
WordPressが自動で作る色の変数
theme.json の settings.color.palette に色を登録すると、WordPressはそれぞれの色についてCSS変数とクラスを自動で出力します。
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"color": {
"palette": [
{ "slug": "primary", "color": "#2563eb", "name": "Primary" },
{ "slug": "base", "color": "#ffffff", "name": "Base" },
{ "slug": "contrast", "color": "#111827", "name": "Contrast" }
]
}
}
}
この例では --wp--preset--color--primary などの変数と、ブロックで色を選んだときに付く .has-primary-color、.has-primary-background-color といったクラスが生成されます。クラスの中身は変数を参照しているため、変数の値が変われば、その色を選んだすべてのブロックの色が変わります。これが動的な色変更の土台になります。
また、settings.custom に書いた値は --wp--custom-- で始まる変数として出力されます。たとえば "custom": { "accent": { "hover": "#1d4ed8" } } は --wp--custom--accent--hover になります。パレットに出すほどではない補助的な色を置く場所として使えます。
なお、ユーザーがサイトエディターのスタイル(グローバルスタイル)で色を変えると、その内容はデータベース(投稿タイプ wp_global_styles)に保存され、テーマの theme.json より優先されます。「theme.json を変えたのに色が変わらない」場合は、まずグローバルスタイル側で上書きされていないかを確認してください。
テーマ独自の色変数を一段かませる
テーマのCSSで直接 #2563eb のような値を書くと、色を変えるたびに全ファイルを探して直すことになります。そこで、CSS側では役割名の変数だけを使い、その中身を1か所で決める構成にします。
:root {
--mytheme-accent: var(--wp--preset--color--primary, #2563eb);
--mytheme-accent-hover: color-mix(in srgb, var(--mytheme-accent) 80%, black);
--mytheme-on-accent: #ffffff;
}
.mytheme-button {
background-color: var(--mytheme-accent);
color: var(--mytheme-on-accent);
}
.mytheme-button:hover,
.mytheme-button:focus-visible {
background-color: var(--mytheme-accent-hover);
}
ポイントは3つあります。
- 接頭辞を付ける:
--wp--preset--で始まる変数はWordPressが管理するものです。自分で同じ名前を上書きすると、出力順や詳細度の関係で効いたり効かなかったりするため、独自の変数には--mytheme-のような接頭辞を付けて分けます。 - フォールバックを書く:
var(--wp--preset--color--primary, #2563eb)の2つ目の値は、変数が未定義のときに使われます。パレットの slug を変えたときに色が消えるのを防げます。 - 派生色は計算する:
color-mix()を使うと、ホバー時の濃い色などを元の色から計算できます。主要ブラウザで使える状態ですが、古いブラウザを考慮する場合は通常の色指定を先に書いておきます(2026年10月現在)。
セクションごとに色を変えたいときは、そのセクションに変数を上書きするクラスを付けるだけで済みます。
.mytheme-campaign {
--mytheme-accent: #dc2626;
}
カスタムプロパティは親要素から子要素へ引き継がれるため、mytheme-campaign クラスを付けたグループブロックの中にあるボタンは、CSSを追加しなくても赤になります。ブロックの「高度な設定」にある追加CSSクラスの欄でクラス名を付ければ、エディターからも使えます。
設定値からPHPで変数を出力する(クラシックテーマ)
カスタマイザーで選んだ色をサイトに反映する例です。子テーマの functions.php に書きます。まず設定とカラーピッカーを登録します。
add_action( 'customize_register', function ( $wp_customize ) {
$wp_customize->add_setting( 'mytheme_accent', array(
'default' => '#2563eb',
'sanitize_callback' => 'sanitize_hex_color',
) );
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'mytheme_accent', array(
'label' => 'アクセントカラー',
'section' => 'colors',
) ) );
} );
次に、保存された値を wp_add_inline_style() で変数として出力します。
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_style(
'mytheme-child',
get_stylesheet_uri(),
array(),
wp_get_theme()->get( 'Version' )
);
$accent = sanitize_hex_color( get_theme_mod( 'mytheme_accent', '#2563eb' ) );
if ( ! $accent ) {
$accent = '#2563eb';
}
wp_add_inline_style( 'mytheme-child', ':root{--mytheme-accent:' . $accent . ';}' );
} );
ここでつまずきやすい点を挙げます。
- 値の検証:設定値をそのままCSSに埋め込むと、想定外の文字列が入ったときにCSSが壊れたり、
</style>を含む値で別のタグを差し込まれたりするおそれがあります。保存時のsanitize_callbackに加え、出力直前にもsanitize_hex_color()で形式を確認しています。 - インラインスタイルの付け先:
wp_add_inline_style()の第1引数には、実際に読み込まれているスタイルのハンドル名を指定します。存在しないハンドルを指定すると何も出力されません。 - 子テーマのCSSの読み込み:親テーマのCSSを子テーマ側で読み込む必要があるテーマもあります。テーマの説明に従ってください。
ブロックテーマでは、カスタマイザーは通常のメニューに表示されないため、次の方法を使います。
ブロックテーマでパレットそのものを動的に変える
ブロックテーマでは、WordPress 6.1 で追加された wp_theme_json_data_theme フィルターを使うと、テーマの theme.json の内容をPHPから書き換えられます。パレットの色を設定値に応じて差し替えれば、.has-primary-color などのクラスもそのまま新しい色になります。
add_filter( 'wp_theme_json_data_theme', function ( $theme_json ) {
$accent = sanitize_hex_color( get_option( 'mytheme_accent', '#2563eb' ) );
if ( ! $accent ) {
return $theme_json;
}
return $theme_json->update_with( array(
'version' => 3,
'settings' => array(
'color' => array(
'palette' => array(
array( 'slug' => 'primary', 'color' => $accent, 'name' => 'Primary' ),
array( 'slug' => 'base', 'color' => '#ffffff', 'name' => 'Base' ),
array( 'slug' => 'contrast', 'color' => '#111827', 'name' => 'Contrast' ),
),
),
),
) );
} );
mytheme_accent というオプションは、テーマやプラグインの設定画面で保存する前提の例です。設定画面を作る場合は、保存処理に権限チェックとnonceの確認を入れてください。
注意点として、パレットは色の一覧ごと置き換わる扱いになるため、変えない色も含めて全色を書きます。一部だけを書くと、ほかの色が選べなくなったり、それを使っていたブロックの色が消えたりします。また、ユーザーがグローバルスタイルでパレットを編集している場合はそちらが優先されるので、このフィルターの変更が見えないことがあります。
JavaScriptでその場で切り替える
ユーザー操作で配色を切り替える場合は、ルート要素の変数をJavaScriptで書き換えます。
document.documentElement.style.setProperty( '--mytheme-accent', '#16a34a' );
ダークモードのように配色全体を切り替えるなら、個々の変数を書き換えるより、<html> に data-theme="dark" のような属性を付け、CSS側で [data-theme="dark"] { --mytheme-accent: ...; } と定義を分けておくほうが管理しやすくなります。OSの設定に合わせるだけなら、@media (prefers-color-scheme: dark) の中で変数を上書きする方法もあります。
スクリプトは wp_enqueue_script() で読み込み、選択内容を保存する場合は localStorage などに置きます。ページ表示後に色が変わると一瞬元の色が見えるため、気になる場合は判定を早い段階で行う工夫が必要です。
色を動的に変えるときの注意
- コントラストを確認する:利用者が自由に色を選べると、背景と文字の差が小さくなり読みにくくなることがあります。WCAGでは通常の文字で4.5:1以上のコントラスト比が目安とされています。選べる色を候補から選ぶ形にする、文字色も合わせて切り替える、といった対策が考えられます。
- キャッシュ:インラインスタイルはHTMLに含まれるため、ページキャッシュを使っている場合は設定変更後にキャッシュを削除します。
- エディターとの見た目の差:フロント側だけで変数を出力すると、ブロックエディター内では古い色のままになります。エディターでも同じ色にしたい場合は、theme.json のパレットを変える方法を選ぶか、エディター用のスタイルにも同じ変数を出力します。
- 作業前にバックアップ:
functions.phpの記述ミスはサイト全体のエラーにつながります。子テーマで作業し、ステージング環境で確認してから本番に反映してください。
まとめ
- theme.json のパレットは
--wp--preset--color--{slug}の変数とクラスを生成し、変数の値を変えれば関連する色がまとめて変わります。 - テーマのCSSは接頭辞付きの独自変数を参照させ、値の決定を1か所に集めると、動的な変更がしやすくなります。
- クラシックテーマではカスタマイザーの値を検証したうえで
wp_add_inline_style()で出力します。 - ブロックテーマでは
wp_theme_json_data_themeフィルターでパレット自体を差し替えられますが、グローバルスタイルが優先される点に注意します。 - 色を変えられるようにするほど、コントラストの確認が欠かせません。