antd-ConfigProvider
一、认识
二、语法
2.1 设置变量
import "uno.css";
import "./App.css";
import "./App.scss";
import { ConfigProvider } from "antd";
import city1 from "./images/city1.png";
import AppStyle from "./App.module.scss";
const cssVarKey = "bolawen";
const cssVarPrefix = "bolawen";
function App() {
return (
<ConfigProvider
theme={{
token: {
colorLink: "#d3adf7",
colorPrimary: "#ff85c0",
colorSuccess: '#ffa940'
},
cssVar: {
key: cssVarKey,
prefix: cssVarPrefix,
},
}}
>
<div className={`app ${cssVarKey}`}>
App 页面
<div className={AppStyle.div1}></div>
<img src={city1} />
<div className="m-1"></div>
<div className="p-2 color-Text2"></div>
<div className="box"></div>
<div className="text-ellipsis-2 w-100">
敷设电缆;范德萨范德萨;林凤娇了;附件都说了;就发了;三等奖发了发;啦束带结发;拉数据;
发;苏妲己;啊;发的酸;拉法基;了发的酸;浪费啊;减肥的;是佛i额文峰街道舒服了扩大升级
</div>
<span className="text-ellipsis-2-inline w-100">
敷设电缆;范德萨范德萨;林凤娇了;附件都说了;就发了;三等奖发了发;啦束带结发;拉数据;
发;苏妲己;啊;发的酸;拉法基;了发的酸;浪费啊;减肥的;是佛i额文峰街道舒服了扩大升级
</span>
</div>
</ConfigProvider>
);
}
export default App;
2.2 使用变量
.app {
width: 800px;
height: 800px;
background-color: var(--bolawen-color-primary, blue);
}
三、项目应用
3.1 UnoCss 增量主题色转换
UnoCss
存量主题色转换: 获取 color
、bg-color
、border-color
色值,如果色值为主题色,则转换为 var()
函数变量语法。如果不是,则正常赋值。
import { Preset } from "unocss";
const getSizeValue = (value: string): string => {
if (!value) {
return "";
}
if (value.includes("-")) {
const values = value.split("-");
return values.map(getSizeValue).join(" ");
}
if (isNaN(Number(value))) {
return value;
}
const remSize = parseFloat(value) / 100;
return remSize ? `${remSize}rem` : "0";
};
export const themeColorVarMap = {
Transparent: "transparent",
colorLink: "var(--bolawen-color-link, #d3adf7)",
colorPrimary: "var(--bolawen-color-primary, #ff85c0)",
colorSuccess: "var(--bolawen-color-success, #ffa940)",
};
export const themeColorVars = Object.keys(themeColorVarMap);
export const autoCompleteColors = [
...themeColorVars,
"fff",
"eee",
"e0e0e0",
"f5f5f5",
"ddd",
"ccc",
"bbb",
"aaa",
"222",
"000",
];
export const getColor = (value: string) => {
if (themeColorVarMap[value]) {
return themeColorVarMap[value];
}
return /^[0-9a-zA-Z]+$/.test(value) ? `#${value}` : value;
};
const boxSizeValue = [
"border-box",
"content-box",
"clip",
"visible",
"scroll",
].join("|");
export const preset1: Preset = {
name: "preset1",
rules: [
[
/^color-(.*)$/,
([, c], { theme }) => ({
color: (theme as any).colors[c] || getColor(c),
}),
{
autocomplete: [`color-(${autoCompleteColors.join("|")})`],
},
],
[
/^bg-color-(.*)$/,
([, c], { theme }) => ({
"background-color": (theme as any).colors[c] || getColor(c),
}),
{
autocomplete: [`bg-color-(${autoCompleteColors.join("|")})`],
},
],
[
/^bg-color-(.*)$/,
([, c], { theme }) => ({
"background-color": (theme as any).colors[c] || getColor(c),
}),
{
autocomplete: [`bg-color-(${autoCompleteColors.join("|")})`],
},
]
],
theme: {
colors: themeColorVarMap,
},
};
3.2 PostCss 存量主题色转换
PostCss
存量主题色转换: 自定义 postcss
插件, 将 CSS
中的颜色值转换为 CSS
var
函数,以便在 CSS
中使用统一的颜色变量来替代硬编码的颜色值,从而实现更好的可维护性和主题切换功能。通过 postcss.plugin("postcss-color-to-css-var", function () { ... })
创建插件,该插件会遍历所有 CSS
规则(root.walkDecls)
,查找颜色值并进行替换:
-
插件会查找所有颜色相关的属性(如
background
,color
,border
等),并检查这些属性的值中是否包含在themeVarMap
中定义的颜色。themeVarMap
: 与UI
伙伴确定主题色值。然后针对color
、bg-color
、border-color
定义主题色值映射, 分别定义该属性对应颜色值到CSS
变量的映射。每个颜色值都可以映射到一个对应的CSS
变量名。 -
如果颜色匹配,则使用对应的
CSS
变量来替换原始的颜色值,格式为var(--bolawen-color-xxx, color)
,这样就实现了使用CSS
变量的效果。如果该颜色在CSS
中已经包含了变量,插件不会进行替换。转换过程中, 如果颜色值是十六进制, 会将十六进制色值统一转换为小写 (比如#FFBD2B
会变成#ffbd2b
), 随后统一转换为RGB/RGBA
格式(例如rgb(255, 189, 43)
)。这个操作的目的是确保无论CSS
中如何表示颜色(十六进制、RGB
、RGBA
),都能统一映射到相同的CSS
变量。 -
插件会跳过标记为
postcss-ignore-theme
的声明,这通过检查注释来判断。另外: 如果属性值是!important
,插件也会跳过不做处理。
const postcss = require("postcss");
const VAR_PREFIX = "--bolawen";
const commonColorMap = {
"#ffbd2b": `${VAR_PREFIX}-color-primary`,
"#ffbd2c": `${VAR_PREFIX}-color-primary`,
"#ffbd2a": `${VAR_PREFIX}-color-primary`,
"#ffbd00": `${VAR_PREFIX}-color-primary`,
"#fbbd05": `${VAR_PREFIX}-color-primary`,
"#ffb91f": `${VAR_PREFIX}-color-primary`,
"#ffab00": `${VAR_PREFIX}-color-primary`,
"#ffab2f": `${VAR_PREFIX}-color-primary`,
"#fab400": `${VAR_PREFIX}-color-primary`,
"#f2af2e": `${VAR_PREFIX}-color-primary-hover`,
"#eaa900": `${VAR_PREFIX}-color-primary-active`,
"#eeeeee": `${VAR_PREFIX}-color-fill-secondary`,
"#eee": `${VAR_PREFIX}-color-fill-secondary`,
};
const themeVarMap = [
{
props: ["background", "background-color"],
map: {
...commonColorMap,
"#f8f8f8": `${VAR_PREFIX}-color-bg-layout`,
"#f4f4f4": `${VAR_PREFIX}-color-bg-layout`,
"#f7f8f9": `${VAR_PREFIX}-color-bg-layout`,
"#f1f3f7": `${VAR_PREFIX}-color-bg-layout`,
"#f5f5f5": `${VAR_PREFIX}-color-bg-layout`,
"#ff9800": `${VAR_PREFIX}-color-primary-active`,
"#ffb000": `${VAR_PREFIX}-color-primary-active`,
},
},
{
props: ["color"],
map: {
...commonColorMap,
"#333333": `${VAR_PREFIX}-color-text`,
"#333": `${VAR_PREFIX}-color-text`,
"#222222": `${VAR_PREFIX}-color-text`,
"#222": `${VAR_PREFIX}-color-text`,
"#000000": `${VAR_PREFIX}-color-text`,
"#000": `${VAR_PREFIX}-color-text`,
"#2d2e30": `${VAR_PREFIX}-color-text`,
"#161719": `${VAR_PREFIX}-color-text`,
"#666666": `${VAR_PREFIX}-color-text-secondary`,
"#666": `${VAR_PREFIX}-color-text-secondary`,
"#999999": `${VAR_PREFIX}-color-text-tertiary`,
"#999": `${VAR_PREFIX}-color-text-tertiary`,
},
},
{
props: [
"border",
"border-color",
"border-top",
"border-top-color",
"border-right",
"border-right-color",
"border-bottom",
"border-bottom-color",
"border-left",
"border-left-color",
],
map: {
...commonColorMap,
"#e0e0e0": `${VAR_PREFIX}-color-border`,
"#f5f5f5": `${VAR_PREFIX}-color-border-secondary`,
"#f7f8f9": `${VAR_PREFIX}-color-border-secondary`,
"#f5f6f7": `${VAR_PREFIX}-color-border-secondary`,
"#f4f4f4": `${VAR_PREFIX}-color-border-secondary`,
},
},
];
function hexToRgb(hex) {
hex = hex.replace("#", "");
if (hex.length === 3 || hex.length === 4) {
hex = hex
.split("")
.map((h) => h + h)
.join("");
}
const bigint = parseInt(hex.substring(0, 6), 16);
const r = (bigint >> 16) & 255;
const g = (bigint >> 8) & 255;
const b = bigint & 255;
return `rgb(${r}, ${g}, ${b})`;
}
function hexToRgba(hex, alpha = 1) {
const rgb = hexToRgb(hex);
return rgb.replace("rgb", "rgba").replace(")", `, ${alpha})`);
}
function generateThemeVarMap(themeVarMap) {
const newThemeVarMap = JSON.parse(JSON.stringify(themeVarMap));
newThemeVarMap.forEach((theme) => {
const clonedMap = { ...theme.map };
Object.keys(theme.map).forEach((hex) => {
const cssVar = clonedMap[hex];
clonedMap[hex.toLowerCase()] = cssVar;
clonedMap[hexToRgb(hex)] = cssVar;
clonedMap[hexToRgba(hex)] = cssVar;
});
theme.map = clonedMap;
});
return newThemeVarMap;
}
const AllThemeVarMap = generateThemeVarMap(themeVarMap);
const colorToCssVar = postcss.plugin("postcss-color-to-css-var", function () {
return (root) => {
root.walkDecls((decl) => {
if (
decl.prev() &&
decl.prev().type === "comment" &&
decl.prev().text.trim() === "postcss-ignore-theme"
) {
return;
}
if (decl.important) {
return;
}
AllThemeVarMap.forEach((varMap) => {
const { props, map } = varMap;
if (props.includes(decl.prop)) {
Object.keys(map).forEach((color) => {
const cssVar = map[color];
const regex = new RegExp(`${color.replace("#", "\\#")}`, "gi");
if (regex.test(decl.value) && !decl.value.includes(VAR_PREFIX)) {
decl.value = decl.value.replace(
regex,
`var(${cssVar}, ${color})`
);
}
});
}
});
});
};
});
module.exports = colorToCssVar;
module.exports = {
plugins: [
"autoprefixer",
"postcss-preset-env",
require("./postcss-color-to-css-var"),
[
"postcss-pxtorem",
{
rootValue: 100,
unitPrecision: 5,
propList: ["*"],
selectorBlackList: [],
minPixelValue: 1,
mediaQuery: false,
},
],
],
};
3.3 ConfigProvider 动态更新主题色
import "uno.css";
import "./App.css";
import "./App.scss";
import { ConfigProvider } from "antd";
import city1 from "./images/city1.png";
import AppStyle from "./App.module.scss";
const cssVarKey = "bolawen";
const cssVarPrefix = "bolawen";
function App() {
return (
<ConfigProvider
theme={{
token: {
colorLink: "#d3adf7",
colorPrimary: "#ff85c0",
colorSuccess: "#ffa940",
},
cssVar: {
key: cssVarKey,
prefix: cssVarPrefix,
},
}}
>
<div className={`app ${cssVarKey}`}>
App 页面
<div className={AppStyle.div1}></div>
<img src={city1} />
<div className="m-1 bg-color-colorSuccess"></div>
<div className="p-2 color-colorLink"></div>
<div className="box"></div>
<div className="text-ellipsis-2 w-100 color-colorPrimary">
敷设电缆;范德萨范德萨;林凤娇了;附件都说了;就发了;三等奖发了发;啦束带结发;拉数据;
发;苏妲己;啊;发的酸;拉法基;了发的酸;浪费啊;减肥的;是佛i额文峰街道舒服了扩大升级
</div>
<span className="text-ellipsis-2-inline w-100 color-colorSuccess">
敷设电缆;范德萨范德萨;林凤娇了;附件都说了;就发了;三等奖发了发;啦束带结发;拉数据;
发;苏妲己;啊;发的酸;拉法基;了发的酸;浪费啊;减肥的;是佛i额文峰街道舒服了扩大升级
</span>
</div>
</ConfigProvider>
);
}
export default App;