element-plus/docs/en-US/guide/theming.md

255 lines
6.7 KiB
Markdown

---
title: Theming
lang: en-US
---
# Custom theme
Element Plus uses BEM-styled CSS so that you can override styles easily. But if
you need to replace styles at a large scale, e.g. change the theme color from
blue to orange or green, maybe overriding them one by one is not a good idea.
We provide four ways to change the style variables.
## Change theme color
These are examples about custom theme.
- Full import: [element-plus-vite-starter](https://github.com/element-plus/element-plus-vite-starter)
- On demand: [unplugin-element-plus/examples/vite](https://github.com/element-plus/unplugin-element-plus)
### By SCSS variables
`theme-chalk` is written in SCSS.
You can find SCSS variables in [`packages/theme-chalk/src/common/var.scss`](https://github.com/element-plus/element-plus/blob/dev/packages/theme-chalk/src/common/var.scss).
::: warning
We use sass modules ([sass:map](https://sass-lang.com/documentation/values/maps)...) and `@use` to refactor all SCSS variables.
> [Introducing Sass Modules | CSS-TRICKS](https://css-tricks.com/introducing-sass-modules/)
For example, We use `$colors` as a map to preserve different types of colors.
`$notification` is a map where all variables of the `notification` component at.
In the future, we will write documentation for variables that can be customized for each component. You can also directly checkout the source [var.scss](https://github.com/element-plus/element-plus/blob/dev/packages/theme-chalk/src/common/var.scss).
:::
```scss
$colors: () !default;
$colors: map.deep-merge(
(
'white': #ffffff,
'black': #000000,
'primary': (
'base': #409eff,
),
'success': (
'base': #67c23a,
),
'warning': (
'base': #e6a23c,
),
'danger': (
'base': #f56c6c,
),
'error': (
'base': #f56c6c,
),
'info': (
'base': #909399,
),
),
$colors
);
```
### How to override it?
If your project also uses SCSS, you can directly change Element Plus style variables. Create a new style file, e.g. `styles/element/index.scss`:
::: warning
You should use `@use 'xxx.scss' as *;` instead of `@import 'xxx.scss';`.
Because the sass team said they will remove `@import` eventually.
> [Sass: @use](https://sass-lang.com/documentation/at-rules/use) vs [Sass: @import](https://sass-lang.com/documentation/at-rules/import)
:::
```scss
// styles/element/index.scss
/* just override what you need */
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$colors: (
'primary': (
'base': green,
),
)
);
// If you just import on demand, you can ignore the following content.
// if you want to import all styles:
// @use "element-plus/theme-chalk/src/index.scss" as *;
```
Then in the entry file of your project, import this style file instead of Element's built CSS:
::: tip
Import `element/index.scss` before scss of element-plus to avoid the problem of sass mixed variables, because we need generate light-x by your custom variables.
:::
Create a `element/index.scss` to combine your variables and variables of element-plus. (If you import them in ts, they will not be combined.)
::: tip
In addition, you should distinguish your scss from the element variable scss.
If they are mixed together, each hot update of `element-plus` needs to compile a large number of scss files, resulting in slow speed.
:::
```ts
import { createApp } from 'vue'
import './styles/element/index.scss'
import ElementPlus from 'element-plus'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
```
If you are using vite, and you want to custom theme when importing on demand.
Use `scss.additionalData` to compile variables with scss of every component.
```ts
import path from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// You can also use unplugin-vue-components
// import Components from 'unplugin-vue-components/vite'
// import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// or use unplugin-element-plus
import ElementPlus from 'unplugin-element-plus/vite'
// vite.config.ts
export default defineConfig({
resolve: {
alias: {
'~/': `${path.resolve(__dirname, 'src')}/`,
},
},
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "~/styles/element/index.scss" as *;`,
},
},
},
plugins: [
vue(),
// use unplugin-vue-components
// Components({
// resolvers: [
// ElementPlusResolver({
// importStyle: "sass",
// // directives: true,
// // version: "1.2.0-beta.1",
// }),
// ],
// }),
// or use unplugin-element-plus
ElementPlus({
useSource: true,
}),
],
})
```
If you are using webpack, and you want to custom theme when importing on demand.
```ts
// webpack.config.ts
// use unplugin-element-plus
import ElementPlus from 'unplugin-element-plus/webpack'
export default defineConfig({
css: {
loaderOptions: {
scss: {
additionalData: `@use "~/styles/element/index.scss" as *;`,
},
},
},
plugins: [
ElementPlus({
useSource: true,
}),
],
})
```
### By CSS Variable
CSS Variables is a very useful feature, already supported by almost all browsers. (IE: Wait?)
> Learn more from [Using CSS custom properties (variables) | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)
We have used css variables to reconstruct the style system of almost all components. (Since `1.0.2-beta-70` [#2242](https://github.com/element-plus/element-plus/issues/2242))
::: tip
It is compatible with the SCSS variable system. We use the function of SCSS to automatically generate css variables for use.
:::
This means you can dynamically change individual variables inside the component to better customize it without having to modify scss and recompile it.
> In the future, the css variable names and role documentation for each component will be written to each component.
Like this:
```css
:root {
--el-color-primary: green;
}
```
If you just want to customize a particular component, just add inline styles for certain components individually.
```html
<el-tag style="--el-tag-bg-color: red">Tag</el-tag>
```
For performance reasons, it is more recommended to custom css variables under a class rather than the global `:root`.
```css
.custom-class {
--el-tag-bg-color: red;
}
```
If you want to control css var by script, try this:
```ts
// document.documentElement is global
const el = document.documentElement
// const el = document.getElementById('xxx')
// get css var
getComputedStyle(el).getPropertyValue(`--el-color-primary`)
// set css var
el.style['--el-color-primary'] = 'red'
```
If you want a more elegant way, check this out.
[useCssVar | VueUse](https://vueuse.org/core/usecssvar/)