定制主题
Ant Design 设计规范上支持一定程度的样式定制,以满足业务和品牌上多样化的视觉需求,包括但不限于主色、圆角、边框和部分组件的视觉定制。
定制方式
Ant Design 的样式使用了 Less 作为开发语言,并定义了一系列全局/组件的样式变量,你可以根据需求进行相应调整,默认样式变量
Ant Design React 的主题定制文件在
ng-zorro-antd
中同样可以使用。
初始化项目时定制主题
在初始化项目时 ng add ng-zorro-antd
时选择自定义主题即可自动配置好自定义主题的相关文件,修改 src/theme.less
文件内容就可以自定义主题。
手动修改
在 src
目录下建立一个单独的 theme.less
文件,在 angular.json
文件的 styles
列表加入该文件
...
"styles": [
...
"src/theme.less"
...
]
...
theme.less
样例如下
在样例中通过修改
@primary-color
的数值将ng-zorro-antd
的基础色修改为#f5222d
,开发者可以根据实际需求自由修改。
// -------- 引入官方提供的 less 样式入口文件 -----------
@import "../node_modules/ng-zorro-antd/ng-zorro-antd.less";
// -------- 自定义参数覆盖 -----------
@primary-color : #f5222d;
在 webpack 中定制主题
Angular CLI 提供了 custom-webpack 的 builder,可以通过该 builder 轻松的调整 webpack 中 less-loader 的配置来进行主题配置。
- 在
angular.json
中引入ng-zorro-antd.less
文件
{
"styles": [
"node_modules/ng-zorro-antd/ng-zorro-antd.less"
]
}
- 安装
@angular-builders/custom-webpack
builder
npm i -D @angular-builders/custom-webpack
- 新建 webpack 配置文件
extra-webpack.config.js
module.exports = {
module: {
rules: [
{
test : /\.less$/,
loader: 'less-loader',
options: {
modifyVars: { // 修改主题变量
'primary-color': '#1DA57A',
'link-color': '#1DA57A',
'border-radius-base': '2px'
},
javascriptEnabled: true
}
}
]
}
};
- 在
angular.json
中配置自定义 builder
"architect": {
"build": {
- "builder": "@angular-devkit/build-angular:browser",
+ "builder": "@angular-builders/custom-webpack:browser",
"options": {
+ "customWebpackConfig": {
+ "path": "./extra-webpack.config.js",
+ "mergeStrategies": {
+ "module.rules": "append"
+ },
+ "replaceDuplicatePlugins": true
+ }
...
},
...
},
"serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
+ "builder": "@angular-builders/custom-webpack:dev-server",
...
}
...
}
更多在 Angular CLI 中定制 webpack 的文章可以参考
- Angular Builder Document
- Angular CLI: Custom webpack Config
- Customize Webpack Configuration in Your Angular Application
全部可被自定义 less 变量可以参考 这里。
官方主题
我们提供了一些官方主题,欢迎在项目中试用,并且给我们提供反馈。
- 🌑 暗黑主题(9+ 支持)
- 📦 紧凑主题(9+ 支持)
方式一
是在样式文件全量引入 ng-zorro-antd.dark.less
或 ng-zorro-antd.compact.less
覆盖主题变量。
@import "~ng-zorro-antd/ng-zorro-antd.dark.less"; // 引入官方提供的暗色 less 样式文件
@import "~ng-zorro-antd/ng-zorro-antd.compact.less"; // 引入官方提供的紧凑 less 样式文件
方式二
如果项目不使用 Less,可在 CSS 文件或者 angular.json
的 styles
字段中,全量引入 ng-zorro-antd.dark.css
或者 ng-zorro-antd.compact.css
。
样式文件中:
@import "~ng-zorro-antd/ng-zorro-antd.dark.css";
angular.json 中
{
"build": {
"options": {
"styles": [
"node_modules/ng-zorro-antd/ng-zorro-antd.dark.css"
]
}
}
}
方式三
在 webpack中 使用 less-loader 按需引入
const darkThemeVars = require('ng-zorro-antd/dark-theme');
const compactThemeVars = require('ng-zorro-antd/compact-theme');
module.exports = {
module: {
rules: [
{
test : /\.less$/,
loader: 'less-loader',
options: {
modifyVars: {
'hack': `true;@import "${require.resolve('ng-zorro-antd/style/color/colorPalette.less')}";`,
...darkThemeVars,
...compactThemeVars
},
javascriptEnabled: true
}
}
]
}
};
主题切换
当使用 @angular/cli 的方式配置主题时必须为每个主题单独打包应用,当你想切换主题而不重新加载应用时(就像这个网站),你可以使用下面的方法将主题编译到单独的样式文件,并在运行时切换:
注意:确保与主题变量相关的样式存在全局样式中,而不是组件样式中,因为组件样式优先级更高将会导致样式无法被覆盖。
- 安装依赖
npm i less -D less-plugin-clean-css -D
- 编写脚本
以黑暗主题为例,使用 less
编译应用的样式入口文件,并且在 modifyVars
参数中替换样式变量,并输出到目标位置。
const less = require('less');
const LessPluginCleanCSS = require('less-plugin-clean-css');
const fs = require('fs');
const darkThemeVars = require('ng-zorro-antd/dark-theme');
const appStyles = 'path/src/styles.less'; // 应用的样式入口文件
const themeContent = `@import '${appStyles}';`;
less.render(themeContent, {
javascriptEnabled: true,
plugins: [new LessPluginCleanCSS({ advanced: true })],
modifyVars: {
...darkThemeVars
}
}).then(data => {
fs.writeFileSync(
// 主题样式的输出文件
'path/assets/themes/style.dark.css',
data.css
)
}).catch(e => {
// 记录渲染错误
console.error(e);
});
- 运行时切换样式
动态创建 link
标签,将样式文件动态加载在应用中,反之移除。
changeTheme(theme: 'default' | 'dark'): void {
if (theme === 'dark') {
const style = document.createElement('link');
style.type = 'text/css';
style.rel = 'stylesheet';
style.id = 'dark-theme';
style.href = 'assets/themes/style.dark.css';
} else {
const dom = document.getElementById('dark-theme');
if (dom) {
dom.remove();
}
}
}