ABOUT ME

-

  • [ Vue ] 다크모드 화이트모드 시스템 테마 설정하기
    Front/Vue 2025. 5. 18. 18:27
    반응형

    이전에 react에서 했던 다크모드와 화이트모드 설정은 직접 class를 하나씩 주는 방식으로 했었는데

    이 부분에서 많은 노가다가 필요했었기에 보통 페이지들에서 사용하는 방식인

    data-theme을 주는 방식으로 진행


    Style

    style 폴더에서 variable.css파일을 생성하여 스타일 변수를 저장하는 파일로 관리

    이후 main에 해당 css파일을 import해주면 된다.

     

    data-theme이 white는 화이트 모드

    data-theme이 dark는 다크모드

     

    이때 변수명은 둘다 동일하게 가져가야한다.

    :root {
        --app-root-padding: 10px;
    }
    
    :root[data-theme='white'] {
        --app-theme-side-background: #f3f3f3;
        --app-theme-background: #FFFFFF;
        --app-theme-text-color: #373737;
    }
    
    :root[data-theme='dark'] {
        --app-theme-side-background: #212121;
        --app-theme-background: #303030;
        --app-theme-text-color: #FFFFFF;
    }

     

     

     

     

     

     

     

    이후 vue파일에서 각 theme에 선언한 css 변수를 넣어주면 된다.

    그럼 이제 dom에서 data-theme이 바뀜에 따라서 해당 변수의 색을 가져오므로
    해당 변수만 적절한 위치에 선언해주면 된다.

    <template>
      <div class="app-layout-wrapper">
        <div class="layout-sidebar">
          <side/>
        </div>
        <div class="layout-main">
          <app-main/>
        </div>
      </div>
    
    </template>
    
    <style scoped lang="scss">
    .app-layout-wrapper {
      width: 100vw;
      height: 100vh;
      display: flex;
    
      .layout-sidebar {
        flex: 20;
        background: var(--app-theme-side-background);
        color: var(--app-theme-text-color);
      }
      .layout-main {
        flex: 80;
        background: var(--app-theme-background);
        color: var(--app-theme-text-color)
      }
    }
    </style>

    Script

    이제 data-theme을 변경해주는 함수를 만들어야한다.

    나중에 오타를 방지하기 위해서 whte와 dark값을 변수로 미리 만들어서 사용

    /* app theme relation */
    export const APP_THEME_KEY = 'app-theme'
    
    export const APP_THEME_WHITE = 'white'
    export const APP_THEME_DARK = 'dark'
    
    export type appThemeWhtie = typeof APP_THEME_WHITE
    export type appThemeDark = typeof APP_THEME_DARK

     

    appTheme함수를 만들어 초기 세팅용 init과 테마 적용용 get/set 함수를 생성

    document.documentElement.setAttribute('data-theme', theme)

    window.matchMedia('(prefers-color-scheme: dark)').matches;

     

    window.matchMedia를 활용하면 시스템 테마를 가져 올 수 있다.

    초기에 설정된 테마가 없다면 시스템 테마를 가져온다.

    이때 시스템 테마는 true, false로 return되면 prefers-color-scheme가 dark인지 아닌지 비교해서 가져온다.

    import type {appThemeDark, appThemeWhite} from "@/constant/local-storage.ts";
    import {APP_THEME_KEY, APP_THEME_WHITE} from "@/constant/local-storage.ts";
    
    export function appTheme() {
        const initTheme = () => {
            const theme = getTheme()
            if(!theme) {
                const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
                systemPrefersDark ? setTheme(APP_THEME_DARK) : setTheme(APP_THEME_WHITE)
            } else {
                setTheme(theme)
            }
        }
    
        const setTheme = (theme: appThemeWhite | appThemeDark) => {
            localStorage.setItem(APP_THEME_KEY,theme)
            document.documentElement.setAttribute('data-theme', theme);
        }
    
        const getTheme = (): appThemeWhite | appThemeDark | null => {
            const theme = localStorage.getItem(APP_THEME_KEY);
            return theme as appThemeWhite | appThemeDark | null;
        }
    
        return {
            initTheme,
            setTheme,
            getTheme
        }
    }

     


    Vue

    그럼 이제 처음 실행시에는 app.vue가 먼저 실행되므로 해당 부분에서 getTheme을 호출해 테마를 적용시켜준다.

    import { createApp } from 'vue'
    import ElementPlus from 'element-plus';
    import 'element-plus/dist/index.css';
    import './style/index.scss'
    import App from './App.vue'
    import router from "@/router";
    import {appTheme} from "@/service";
    const {initTheme} = appTheme()
    
    initTheme()
    
    const app = createApp(App)
    
    app.use(ElementPlus)
    app.use(router)
    app.mount('#app')

     

    이제 스위치를 통해서 값이 변경되면 setTheme을 호출해서 테마를 바꿔준다.

    element-plus를 사용하므로 el-switch를 사용

    import {appTheme} from "@/service";
    
    const {setTheme,getTheme} = appTheme()
    const themeMode = ref(getTheme())
    
    const appThemeChange = (theme: appThemeWhtie | appThemeDark) => {
      setTheme(theme)
    }
    </script>
    
    <template>
      <div class="app-side-wrapper">
        <div class="side-mode-change">
          <div class="flex-center">다크모드</div>
          <el-switch v-model="themeMode"
                     :active-value="APP_THEME_DARK"
                     :inactive-value="APP_THEME_WHITE"
                     @change="appThemeChange"
          />
        </div>
    
      </div>
    </template>

     

    watch를 활용해서 할까 하다가 그냥 @change로 사용

    728x90
    반응형

    'Front > Vue' 카테고리의 다른 글

    [ Vite + Vue ] Svg Loader, svg 아이콘 컴포넌트  (0) 2025.06.03