主题与 UI 样式
让 @ydesign/react-editor 的外观和你自己的产品品牌融合,是日常接入中最常见的需求之一。本页梳理 @ydesign 的样式技术栈,以及调整主题色、开启暗色模式、覆盖局部样式的三种方式。
样式栈一览
@ydesign/react-editor 并没有绑死某一套 UI 框架,而是把几种成熟方案按"各司其职"的方式组合起来:
| 层级 | 技术选型 | 用途 |
|---|---|---|
| 组件库 | Ant Design v6 | 按钮、下拉、弹窗、输入框等 UI 组件 |
| 主题令牌 | Antd Design Token(theme.useToken()) | 颜色、圆角、字号、间距等设计变量,运行时可读 |
| 原子类 | Tailwind CSS v4 | 面板布局、间距、Flex 等快速样式 |
| 布局容器 | styled-components | DesignEditorContainer / SidePanelWrap / WorkspaceWrap 等响应式容器 |
| 编辑器核心 | 无样式依赖 | @ydesign/core 本身不引入任何 CSS |
也就是说,你在调主题时有三个独立的抓手:Antd ConfigProvider、Tailwind 暗色模式、原始 CSS 覆盖。
1. 通过 ConfigProvider 配置主题色
这是推荐的第一步。把整个编辑器包在 Antd 的 <ConfigProvider /> 里,编辑器内部所有组件都会自动跟随:
import { ConfigProvider, theme } from 'antd';
import { DesignEditorApp } from '@ydesign/react-editor';
export default function App() {
return (
<ConfigProvider
theme={{
token: {
colorPrimary: '#ff6a00', // 主题色
colorInfo: '#ff6a00',
borderRadius: 6, // 全局圆角
fontFamily: 'Inter, -apple-system, sans-serif',
},
}}
>
<DesignEditorApp store={store} />
</ConfigProvider>
);
}
内部代码里很多组件是这么读主题色的:
import { theme } from 'antd';
const { token } = theme.useToken();
// token.colorPrimary、token.colorBgContainer、token.borderRadius ...
也就是说,只要你改了 ConfigProvider 里的 token,侧边面板、工具栏、Topbar 等组件都会同步变化,不需要额外的 CSS 覆盖。
2. 开启暗色模式
@ydesign/react-editor 的暗色模式由两个开关共同组成:Antd 的暗色算法 + Tailwind 的 dark 变体。
2.1 Antd 暗色算法
import { ConfigProvider, theme } from 'antd';
<ConfigProvider
theme={{
algorithm: theme.darkAlgorithm, // 👈 关键
token: {
colorPrimary: '#ff6a00',
},
}}
>
<DesignEditorApp store={store} />
</ConfigProvider>;
2.2 Tailwind 暗色模式
Tailwind 配置的是 darkMode: ['class', '[data-theme="dark"]'],意味着任何带有 data-theme="dark" 属性(或 .dark 类名)的祖先元素都会触发 Tailwind 的 dark: 变体。
最简单的做法是给 <html> 或 <body> 加一个属性:
<html data-theme="dark">
<!-- ... -->
</html>
或者在运行时切换:
document.documentElement.setAttribute('data-theme', 'dark');
// 切回亮色
document.documentElement.removeAttribute('data-theme');
2.3 暗色 / 亮色一键切换示例
下面是一个完整的主题切换组件,供参考:
import { useState } from 'react';
import { ConfigProvider, theme, Button } from 'antd';
import { DesignEditorApp } from '@ydesign/react-editor';
export default function App({ store }) {
const [isDark, setIsDark] = useState(false);
const toggle = () => {
const next = !isDark;
setIsDark(next);
document.documentElement.setAttribute('data-theme', next ? 'dark' : 'light');
};
return (
<ConfigProvider
theme={{
algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm,
token: { colorPrimary: '#ff6a00' },
}}
>
<Button onClick={toggle}>切换主题</Button>
<DesignEditorApp store={store} />
</ConfigProvider>
);
}
3. 覆盖组件的局部样式
Antd token 覆盖不了的细节(例如侧边面板 Tab 的选中态颜色、某个按钮 hover 时的背景),可以通过 CSS 覆盖。所有内部组件都有稳定的 class 名,可以放心当选择器使用。
3.1 常用稳定类名
| 类名 | 对应组件 |
|---|---|
.polotno-app-container | 编辑器最外层容器(DesignEditorApp) |
.polotno-side-tabs-container | 侧边 Tab 容器(纵向图标列) |
.polotno-side-panel-tab | 每一个侧边 Tab 按钮 |
.polotno-side-panel-tab.active | 选中态 Tab |
.polotno-font-item | 文字面板里的字体项 |
.polotno-close-panel | 侧边面板右上角的关闭按钮 |
ℹ️ 上述类名前缀
polotno-是历史命名遗留,后续会逐步迁移为ydesign-,届时会通过别名保证向后兼容。
3.2 覆盖示例
/* 自定义侧边 Tab 的 hover 与选中态 */
.polotno-side-tabs-container .polotno-side-panel-tab:hover,
.polotno-side-tabs-container .polotno-side-panel-tab.active {
background-color: #ff6a00;
color: #fff;
}
/* 暗色模式下的 Tab 高亮 */
[data-theme='dark'] .polotno-side-panel-tab.active {
background-color: #ff8a3d;
}
/* 编辑器容器背景 */
.polotno-app-container {
background: #1e1e1e;
}
/* 画布工作区(带渐变底)*/
.polotno-app-container .polotno-workspace-container {
background: radial-gradient(circle, #2a2a2a, #181818);
}
3.3 定位类名的技巧
如果你想调整某个具体细节却找不到 class 名,最简单的方式是在浏览器里打开开发者工具 → 选中元素 → 查看 DOM。@ydesign/react-editor 大量使用 styled-components,生成的类名虽然带哈希,但父级的稳定类名(上表里那些)足够你写出具体选择器。
4. 字体主题
编辑器的UI 字体跟 Antd token 的 fontFamily 走。编辑器内画布里元素的字体与此独立,由 store.fonts 和全局字体管理(见 编辑器配置 · 字体管理)。
<ConfigProvider
theme={{
token: {
fontFamily: '"PingFang SC", "Helvetica Neue", sans-serif',
},
}}
>
<DesignEditorApp store={store} />
</ConfigProvider>
5. 跟随系统暗色
如果希望跟随用户操作系统的设置:
import { useEffect, useState } from 'react';
function useSystemTheme() {
const [isDark, setIsDark] = useState(() => window.matchMedia('(prefers-color-scheme: dark)').matches);
useEffect(() => {
const mq = window.matchMedia('(prefers-color-scheme: dark)');
const handler = (e: MediaQueryListEvent) => setIsDark(e.matches);
mq.addEventListener('change', handler);
return () => mq.removeEventListener('change', handler);
}, []);
useEffect(() => {
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
}, [isDark]);
return isDark;
}
在组件中:
const isDark = useSystemTheme();
<ConfigProvider
theme={{
algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm,
token: { colorPrimary: '#ff6a00' },
}}
>
<DesignEditorApp store={store} />
</ConfigProvider>;
6. 注意事项
- 不要覆盖 Antd 内部的
.ant-*class,一旦 Antd 升级小版本很可能直接失效。改主题请走ConfigProvider。 - Tailwind 的工具类需要在使用方项目里启用 Tailwind。如果你的项目没用 Tailwind,也不影响
@ydesign/react-editor,编辑器内部样式已经打包好。 - 样式文件必须引入:
否则组件会没有样式。
import '@ydesign/react-editor/style.css'; - SSR 场景:Tailwind 的
data-theme属性要在服务端设置好,避免首屏"亮→暗"闪烁。
延伸阅读
- 编辑器配置 —— 运行时配置(上传、i18n、字体、后端)
- 定制化 —— 替换 / 扩展 UI 组件
- Ant Design 主题文档
- Tailwind CSS v4 暗色模式