-
[ 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