想改佈景主題的某個顏色,結果翻遍 style.css 找到十幾處 #3a86ff,改完一個按鈕沒變、改完按鈕標題又跑掉,這種改一處壞三處的經驗,幾乎每個碰過 WordPress 客製化的人都有。問題不在你不夠細心,而在傳統 CSS 把同一個值散寫在幾十個地方,沒有單一的控制點。
CSS 變數(正式名稱是 CSS 自訂屬性,CSS custom properties)就是用來解決這件事的原生語法。把顏色、間距、字級集中宣告成一個變數,全站要用的地方都指向它,往後要換色只動一行。這篇會從語法講到實際怎麼套進 WordPress 佈景主題:包含怎麼找出主題已經在用哪些變數、怎麼在不改動母主題原始碼的前提下覆寫它,以及區塊主題的 theme.json 把變數玩到什麼程度。
CSS 變數是什麼,跟 Sass 變數差在哪
CSS 變數是瀏覽器原生支援的自訂屬性,用兩個連字號 -- 開頭宣告,再用 var() 函式取值。它最關鍵的特性是「執行時可動態改變」,這點和 Sass、Less 那種預處理器變數完全不同。
Sass 變數在編譯成 CSS 的那一刻就被換成固定值,瀏覽器看到的是已經算好的結果,事後無法再改。CSS 變數則一路活到瀏覽器裡,可以被媒體查詢覆寫、被 JavaScript 改寫、被不同的選擇器層層覆蓋。對佈景主題來說,這代表你能做到「切換深色模式只改幾個變數值,全站連動」這種事,Sass 變數做不到。
基本寫法分兩步。先宣告,再用 var() 取用:
:root {
--primary-color: #3a86ff;
--text-color: #333;
--space-md: 16px;
}
.button {
background: var(--primary-color);
padding: var(--space-md);
}
變數名稱區分大小寫,--main 和 --Main 會被當成兩個不同的變數,命名時要一致。
變數宣告在 :root 還是區域選擇器,差在作用範圍
:root 代表文件的根元素,等同於 <html>,把變數宣告在這裡,全站任何元素都取得到,這也是放佈景主題全域色票、間距的標準位置。但變數不是只能宣告在 :root,它遵循 CSS 的層疊與繼承規則,宣告在哪個選擇器,就只有那個元素和它的子元素拿得到。
:root {
--card-bg: #fff; /* 全域:所有元素可用 */
}
.dark-section {
--card-bg: #1a1a1a; /* 區域:只有這塊及其子元素拿到深色 */
}
.card {
background: var(--card-bg);
}
同一個 .card 元件,放在一般區塊是白底,放進 .dark-section 裡就自動變深底,因為它讀到的是離自己最近的那個 --card-bg 宣告。這個「就近覆寫」的特性,是後面做主題切換和局部換色的基礎。
實務上有個常踩的坑:變數宣告寫錯選擇器,導致目標元素根本繼承不到。如果你把 --card-bg 宣告在 .card 的兄弟元素而非父層,.card 讀不到就會落回 var() 的後備值或無效。判斷原則很簡單,用變數的元素,必須是宣告變數那個選擇器的本身或後代。
var() 後備值怎麼用,避免變數失效時版面崩掉
var() 接受第二個參數當後備值,當第一個變數無效或根本沒宣告時,就改用後備值。這在覆寫別人的主題時特別重要,因為你不一定確定對方有沒有定義某個變數。
/* 若 --link-color 沒宣告,就用 #06c */
a {
color: var(--link-color, #06c);
}
後備值也能巢狀,一個變數抓不到就找下一個:
a {
color: var(--link-color, var(--text-color, #333));
}
要注意後備值只在「變數未定義」時生效,不是在「值算出來不合法」時。如果 --link-color 被宣告成 12px 這種不能當顏色的值,瀏覽器不會退回後備值,而是讓整條 color 宣告失效。所以後備值能擋的是「沒這個變數」,擋不了「變數值填錯型別」。
怎麼找出佈景主題已經在用哪些 CSS 變數
覆寫主題前的第一件事,是先搞清楚它定義了哪些變數,而不是憑空新增。多數現代佈景主題都把色票、字級、間距宣告在 :root 或 body,你只要把它們挖出來就能對症下藥。
最直接的做法是用瀏覽器的開發人員工具。在前台頁面按 F12 開啟,選取 <html> 元素,在樣式面板裡找到 :root 或 html 的規則區塊,所有 -- 開頭的宣告會列在那裡。把要改的變數名稱抄下來,例如 --wp--preset--color--primary 或主題自訂的 --theme-accent。
另一個方式是直接看主題的 style.css 或 theme.json。經典主題的變數通常集中在 style.css 開頭的 :root 區塊;區塊主題則是由 theme.json 自動產生(下一段會講)。先找到變數的真實名稱,覆寫才有對象,盲目新增一個主題沒在讀的變數不會有任何效果。
如何在不改母主題原始碼的前提下覆寫變數
知道變數名稱後,覆寫的核心觀念是「重新宣告同一個變數,用更高的層疊優先序蓋過原值」。重點是不要去改母主題的 style.css,因為主題一更新就被覆蓋掉,所有客製化付諸流水。WordPress 有兩條安全路徑。
第一條是「外觀」選單裡的「附加的 CSS」(Additional CSS)。這裡寫的樣式會在主題樣式之後載入,優先序天然較高,適合改個幾項變數:
:root {
--wp--preset--color--primary: #d6336c;
--theme-content-width: 760px;
}
第二條是建立子佈景主題(child theme),把覆寫寫進子主題的 style.css。改動量大、或要長期維護時走這條,因為它和母主題各自獨立,母主題更新不會動到你的覆寫。
如果覆寫沒生效,多半是兩個原因。一是母主題把變數宣告在比 :root 更具體的選擇器(例如 .site-header),你只覆寫 :root 層級壓不過它,得用同樣或更具體的選擇器去蓋。二是變數名稱抄錯,差一個字就無效。遇到不生效,回開發人員工具確認變數名稱和宣告它的選擇器,比硬加 !important 更能根治。
區塊主題的 theme.json 怎麼把變數自動化
如果你用的是區塊主題(block theme,採用全站編輯的那種),多數變數不該手寫 CSS,而是在 theme.json 設定,WordPress 會自動產生對應的 CSS 變數。這是 WordPress 官方目前主推的做法。
在 theme.json 裡定義的色票、字級、間距會被轉成固定命名規則的 CSS 變數。一個 slug 為 primary 的顏色色票,會自動產生 --wp--preset--color--primary;放在 custom 區段的自訂值,則依 --wp--custom--變數名 的規則產生。
{
"version": 2,
"settings": {
"color": {
"palette": [
{ "slug": "primary", "color": "#3a86ff", "name": "主色" }
]
},
"custom": {
"contentWidth": "760px"
}
}
}
上面這段會讓你在任何地方都能用 var(--wp--preset--color--primary) 和 var(--wp--custom--content-width)。在 theme.json 內部互相引用時,則用 var:preset|color|primary 這種專屬語法。
theme.json 的好處是同一份設定同時餵給前台、區塊編輯器、和全站編輯介面,編輯者在後台選色票時看到的選項,和前台實際渲染的變數是同一套,不會各寫各的。經典主題沒有 theme.json,仍需在 style.css 手寫 :root 變數,兩種路線取決於你的主題類型。
用變數做深色模式與響應式,一份宣告連動全站
CSS 變數真正發揮威力的場景,是把它跟媒體查詢、class 切換、JavaScript 組合起來,做到「只改變數值、全站連動」。深色模式是最典型的例子。
做法是把所有會隨主題改變的顏色都抽成變數,淺色當預設值,再用一個選擇器整批覆寫成深色。常見的觸發方式有兩種,一是跟著系統偏好,二是讓使用者手動切換:
:root {
--bg: #fff;
--text: #333;
}
/* 跟隨系統深色偏好 */
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #eee;
}
}
/* 或由按鈕在 <html> 加上 data-theme="dark" 觸發 */
[data-theme="dark"] {
--bg: #1a1a1a;
--text: #eee;
}
body {
background: var(--bg);
color: var(--text);
}
整個版面只要讀的是 var(--bg)、var(--text),切換時不必逐個元件改樣式,改的只有那幾個變數值。手動切換則靠一小段 JavaScript 在 <html> 上加減 data-theme 屬性,並把選擇存進 localStorage,下次載入頁面時自動套用:
const root = document.documentElement;
// 讀使用者上次的選擇
if (localStorage.getItem('theme') === 'dark') {
root.setAttribute('data-theme', 'dark');
}
// 切換按鈕
document.querySelector('.theme-toggle').addEventListener('click', () => {
const isDark = root.getAttribute('data-theme') === 'dark';
root.setAttribute('data-theme', isDark ? 'light' : 'dark');
localStorage.setItem('theme', isDark ? 'light' : 'dark');
});
響應式同理。把字級、間距、欄寬設成變數,在媒體查詢裡只改 :root 的變數值,所有用到的地方一起縮放,不用為每個斷點重寫一堆規則。變數也能搭配 calc() 做衍生計算,例如標題字級設成內文的 1.5 倍,內文一改標題跟著動:
:root {
--font-base: 16px;
}
@media (max-width: 768px) {
:root { --font-base: 14px; }
}
p { font-size: var(--font-base); }
h1 { font-size: calc(var(--font-base) * 1.5); }
用 CSS 變數整理佈景主題前,先想清楚這幾件事
CSS 變數對佈景主題的價值,不在語法多炫,而在它把分散的樣式收斂成單一控制點:色票集中在 :root 或 theme.json,全站指向同一個變數,往後換色、做深色模式、調響應式都只動源頭一處,不再滿檔案找 #3a86ff。覆寫別人的主題時,先用開發人員工具挖出真實的變數名稱,再透過「附加的 CSS」或子主題去重新宣告,避免直接改母主題被更新洗掉。
要留意的是相容性與型別。CSS 變數在現行主流瀏覽器都支援,但 IE 完全不認得,若你的讀者還有 IE 用戶,關鍵樣式得搭配後備值;後備值能擋變數未定義,擋不了值填錯型別,這點要分清楚。區塊主題優先用 theme.json 管理變數,經典主題則在子主題 style.css 手寫 :root,先確認自己的主題屬於哪一種,再決定動手的位置。從整理現有色票開始,把最常改的三五個值抽成變數,你會立刻感覺到客製化從「改一處壞三處」變成「改一行全站連動」。