最近產品經理希望在 B 端後台系統中增加品牌色功能,突顯客户的企業特色。從技術上説,整個流程是非常簡單的:
- 在配置中心為某個客户配置品牌色(十六進制顏色值)。
- 後台系統初始化時,通過後端接口讀取配置的品牌色。
- 把品牌色寫入為根元素的 CSS 變量。
核心流程代碼如下:
const response = await fetch('/api/get-brand-info');
const data = await response.json();
document.documentElement.style.setProperty(
'--brand-primary-color',
data.primaryColor
);
顏色替換
接下來要把項目中樣式代碼的顏色值改為 CSS 變量。顏色值的使用,一般有兩種情況:
- 使用了 SCSS 等 CSS 擴展語言中的變量,所有顏色值都從變量取值;
- 直接用顏色值。
實際情況更有可能是這兩種的混合——雖然使用了 SCSS 變量,但由於部分開發人員沒有完全遵循規範,所以項目中既有顏色變量,也有顏色值。
$primary-color: #3F76FC;
.logo {
background: #3F76FC;
}
.selected {
color: $primary-color;
border: 1px solid $primary-color;
background: rgba($primary-color, 0.1);
}
不過,不管是哪種情況,似乎都是把顏色值替換成 CSS 變量就可以了。以上述代碼為例,即把#3F76FC 替換為 var(--brand-primary-color, #3F76FC):
$primary-color: var(--brand-primary-color, #3F76FC);
.logo {
background: var(--brand-primary-color, #3F76FC);
}
.selected {
color: $primary-color;
border: 1px solid $primary-color;
background: rgba($primary-color, 0.1);
}
替換後,馬上發現問題——.selected 元素的背景色沒了。通過瀏覽器開發工具可以發現,背景屬性的值變成了:
background: rgba(var(--brand-primary-color, #3F76FC), 0.1);
屬於無效寫法。造成這種情況,是因為「background: rgba($primary-color, 0.1)」中的「$primary-color」被編譯成該變量的值了。
在 SCSS 中,可以用「rgba(#3F76FC, 0.1)」這種寫法。編譯過程中,編譯器會把十六進制顏色值轉成 RGB 顏色值,也就是編譯成「rgba(63, 118, 252, 0.1)」。然而,把顏色值替換成 CSS 變量後,由於編譯器也不知道顏色值是什麼,所以無法進行轉換。因此,這裏必須用 RGB 顏色值。
對核心流程代碼稍作修改,設置兩個 CSS 變量,分別是 RGB 顏色值和十六進制顏色值:
import { hexToRGB } from '@polyv/utils/es/color';
const response = await fetch('/api/get-theme');
const data = await response.json();
document.documentElement.style.setProperty(
'--brand-primary-color-hex',
data.primaryColor
);
document.documentElement.style.setProperty(
'--brand-primary-color-rgb',
hexToRGB(data.primaryColor).join(',')
);
接下來設置兩個 SCSS 變量,分別是品牌色的十六進制表示和 RGB 表示:
$--primary-color-hex: var(--brand-primary-color-hex, #3F76FC);
$--primary-color-rgb: var(--brand-primary-color-rgb, 63, 118, 252);
做兩次替換操作:
- 把
rgba($--primary-color以及rgba(#3F76FC替換為rgba($--primary-color-rgb。 - 把剩餘的
$--primary-color以及#3F76FC替換為$--primary-color-hex。
最終能正常運行的代碼為:
$--primary-color-hex: var(--brand-primary-color-hex, #3F76FC);
$--primary-color-rgb: var(--brand-primary-color-rgb, 63, 118, 252);
.logo {
background: $--primary-color-hex;
}
.selected {
color: $--primary-color-hex;
border: 1px solid $--primary-color-hex;
background: rgba($--primary-color-rgb, 0.1);
}
顏色計算
設計師希望後台系統左側導航欄的底色是通過 25% 不透明度的品牌色疊加黑色得出。
雖説通過兩個 HTML 元素疊加,就能做到這個效果,但是 HTML 結構和樣式代碼都會稍顯複雜。通過 JavaScript 去計算出這個顏色值就方便多了:
export function mixWithBlack(color, opacity) {
const r = parseInt(hex.slice(0, 2), 16) * opacity;
const g = parseInt(hex.slice(2, 4), 16) * opacity;
const b = parseInt(hex.slice(4, 6), 16) * opacity;
const toHex = (c) => c.toString(16).padStart(2, '0');
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
document.documentElement.style.setProperty(
'--brand-nav-bg-color',
mixWithBlack(data.primaryColor)
);
如果還有更復雜的顏色計算,也可以使用專業的第三方庫,如 tinycolor。
最終效果
本文也發表在作者個人博客 https://mrluo.life/article/detail/156/technical-implementatio...