커스텀 테마

커스텀 테마 (Custom theme)

출처: 문서

본문

Element Plus는 BEM 스타일의 CSS를 사용해서 스타일을 쉽게 오버라이드할 수 있어요. 하지만 테마 색상을 파란색에서 오렌지나 초록으로 바꾸는 것처럼 스타일을 대규모로 교체해야 한다면, 하나씩 오버라이드하는 건 좋은 방법이 아니겠죠. 스타일 변수를 바꾸는 방법 네 가지를 제공해요.

테마 색상 바꾸기 ​

커스텀 테마에 대한 예시들이에요.

  • 전체 import: element-plus-vite-starter
  • 온디맨드: unplugin-element-plus/examples/vite

SCSS 변수로 ​

theme-chalk는 SCSS로 작성되어 있어요. SCSS 변수는 packages/theme-chalk/src/common/var.scss에서 찾을 수 있습니다.

WARNING sass 모듈(sass:map...)과 @use를 사용해 모든 SCSS 변수를 리팩터링했어요. 모든 SCSS 변수에 @use를 쓰면 @import에서 생기던 중복 출력 문제가 해결돼요. 자세한 내용은 Sass Modules 글을 참고하세요.

예를 들어 $colors는 서로 다른 타입의 색상을 보관하는 map으로 사용돼요. $notification은 notification 컴포넌트의 모든 변수를 담은 map이죠. 앞으로 각 컴포넌트에서 커스터마이즈할 수 있는 변수에 대한 문서도 작성할 예정이에요. 지금은 소스 var.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
);

어떻게 오버라이드할까요? ​

프로젝트도 SCSS를 사용한다면 Element Plus 스타일 변수를 직접 바꿀 수 있어요. 새 스타일 파일(예: styles/element/index.scss)을 만듭니다.

WARNING @import 'xxx.scss'; 대신 @use 'xxx.scss' as *;를 사용해야 해요. sass 팀이 결국 @import를 제거할 예정이기 때문이에요. 관련 글: Sass: @use vs Sass: @import

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 *;

그다음 프로젝트의 엔트리 파일에서 Element의 내장 CSS 대신 이 스타일 파일을 import 해요.

TIP 내 커스텀 변수로 light-x를 생성해야 하므로, sass 변수 혼합 문제를 피하려면 element/index.scss를 element-plus의 scss보다 먼저 import 하세요.

element/index.scss를 만들어 내 변수와 element-plus의 변수를 결합해요. (ts에서 import 하면 결합되지 않아요.)

TIP 또 하나, 내 scss와 element 변수 scss를 분리해야 해요. 섞여 있으면 element-plus의 핫 리로드마다 수많은 scss 파일을 컴파일해야 해서 느려지거든요.

main.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)

vite를 쓰면서 온디맨드 import 시 커스텀 테마를 적용하고 싶다면, scss.additionalData를 사용해 매 컴포넌트의 scss와 함께 변수를 컴파일하면 돼요.

vite.config.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'

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: "2.1.5",
    //     }),
    //   ],
    // }),
    // or use unplugin-element-plus
    ElementPlus({
      useSource: true,
    }),
  ],
})

webpack을 쓰면서 온디맨드 import 시 커스텀 테마를 적용하고 싶다면 이렇게 하세요.

webpack.config.js

// 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,
    }),
  ],
})

CSS 변수로 (By CSS Variable) ​

CSS Variables는 아주 유용한 기능으로, 거의 모든 브라우저에서 지원돼요. 거의 모든 컴포넌트의 스타일 시스템을 css 변수로 재구성했답니다.

TIP SCSS 변수 시스템과 호환돼요. SCSS의 기능으로 css 변수를 자동 생성해서 쓰기 때문이에요.

이 말은 scss를 수정하고 다시 컴파일하지 않아도 컴포넌트 내부의 개별 변수를 동적으로 변경해 더 잘 커스터마이즈할 수 있다는 뜻이에요. 앞으로 각 컴포넌트의 css 변수 이름과 역할 문서도 각 컴포넌트에 작성할 예정이에요. 이렇게 씁니다:

:root {
  --el-color-primary: green;
}

특정 컴포넌트만 커스터마이즈하고 싶다면 해당 컴포넌트에 인라인 스타일을 추가하면 돼요.

<el-tag style="--el-tag-bg-color: red">Tag</el-tag>

성능 때문에 전역 :root보다는 클래스 아래에서 css 변수를 커스터마이즈하는 걸 더 권장해요.

.custom-class {
  --el-tag-bg-color: red;
}

스크립트로 css 변수를 제어하고 싶다면 이렇게 해 보세요.

// 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'

더 우아한 방법을 원한다면 VueUse의 useCssVar를 확인해 보세요.

더 알아보기 (Learn more)