Project Shall-We-Health #4-2 다크 모드/라이트 모드 구현
시작하며
SR에서 기획했던 Bare Minimum과 Advanced 단계의 목표 중 내가 맡은 파트를 끝내서 Nightmare 중 다크 모드 구현을 하게 되었다. 다른 목표들은 서버의 구현이 필요하거나 데이터 베이스의 스키마를 수정해야해서 클라이언트에서 구현이 가능한 다크모드를 우선 구현하였다.
라이트 모드/다크 모드 여부 저장
유저가 다크모드로 변경하면 추후 페이지에 접속하거나 새로고침을 해도 유지가 되어야 하기 때문에 다크모드여부를 따로 저장할 수 있는 공간이 필요했다. state나 redux로 관리하면 새로고침 될때마다 초기화되기 때문에 부적합하고 처음에는 쿠키로 저장해놓을까 고민했었는데, 여러 포스팅을 찾아보면서 localStorage를 사용하는 것이 적절하다는 것을 알게 되었다.
//useTheme.js
import { useState } from 'react';
const useTheme = () => {
const prefersColorScheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
const localTheme = localStorage.getItem('theme');
const initialTheme = localTheme || prefersColorScheme;
const [theme, setTheme] = useState(initialTheme);
const setMode = (mode) => {
localStorage.setItem('theme', mode);
setTheme(mode);
};
const themeToggler = () => {
theme === 'light' ? setMode('dark') : setMode('light');
};
return [theme, themeToggler];
};
export default useTheme;
처음에는 라이트/다크 모드 여부만 localStorage에 저장하고 처음 접속한 경우 라이트 모드가 적용되도록 설정하려고 했었다. 관련된 포스트를 찾아보던 중 prefers-color-scheme
와 window.matchMedia
를 사용하여 유저의 테마를 적용할 수 있는 방법이 잘 정리되어 있는 글을 발견하여 같은 방법을 사용하였다.
참고 포스팅 : Gatsby Blog 다크 모드 적용기
테마 버튼 구현
function App() {
const [theme, themeToggler] = useTheme();
...
return (
<div className='App' data-theme={theme}>
...
{theme==='light' ? (
<div className='btn-theme dark' onClick={()=>{themeToggler()}}><FontAwesomeIcon className='icon-theme' icon={faMoon} /><div>다크 모드로 보기</div></div>
) : (
<div className='btn-theme light' onClick={()=>{themeToggler()}}><FontAwesomeIcon className='icon-theme' icon={faSun} /><div>라이트 모드로 보기</div></div>
)}
</div>
);
}
export default App;
App 컴포넌트에 position:fixed
인 버튼을 생성하고 useTheme의 theme에 따라 보여지는 버튼이 다르게 설정하고 버튼 클릭시 themeToggler()이 실행되어 localStorage의 theme 값이 변경되도록 설정해주었다.
최상단 태그의 속성에 data-theme={theme}
를 추가해주어 theme에 따라 적용되는 CSS가 달라질 수 있도록 설정하였다.
CSS 변수를 사용한 색상 적용
다크모드에 따라 CSS의 color 값이 변경되는 방법이 다양했는데 보통 styled-components를 사용한 방법이 대다수였다. 다크모드 구현을 위해서 웹페이지 전체에 styled-components를 사용하는 방식으로 변경하는 것은 무리여서 다른 방법을 찾던 중 CSS도 변수를 설정할 수 있다는 것을 알게 되었다.
/*APP.css*/
:root {
--main-color1: #39CFD9;
--main-color2: rgb(172, 172, 172);
--btn-color1: rgb(100, 100, 100);
--btn-color2: #FFF;
--nav-color: rgb(211, 211, 211);
--main-backcolor1: #fafafa;
--main-backcolor2: #f4f4f49d;
--main-backcolor3: white;
--main-backcolor4: #656565;
--font-color1: black;
--font-color2: #535353;
--font-color3: rgb(56, 56, 56);
--shadow-color: rgb(187, 187, 187);
}
[data-theme="dark"] {
--main-color1: #367c81;
--main-color2: rgb(88, 86, 86);
--btn-color1: rgb(240, 240, 240);
--btn-color2: rgb(54, 54, 54);
--nav-color: rgb(93, 93, 93);
--main-backcolor1: #202020;
--main-backcolor2: #202020;
--main-backcolor3: rgb(93, 93, 93);
--main-backcolor4: #313131;
--font-color1: white;
--font-color2: #eeeeee;
--font-color3: rgb(233, 233, 233);
--shadow-color: rgb(0, 0, 0);
}
.App {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Apple SD Gothic Neo,arial,sans-serif;
overflow-x: hidden;
background-color: var(--main-backcolor1);
color: var(--font-color1);
}
...
--
로 변수명을 설정해주고 background-color
나 color
값을 var(--변수명)
으로 설정해주면 해당하는 색상으로 적용이 가능하다. 모든 페이지에서 따로 설정할 필요없이 색상만 설정해주고 CSS 변수만 사용하면 구현이 가능하다.
구현 화면
마치며
이전 프로젝트부터 구현해보고 싶었던 기능인데 이번에 경험할 수 있어서 좋은 기회였다. 처음에 다크모드 구현을 생각하지 않고 메인 컬러를 제외하고 각자 color 값을 설정해서 통일시키는데 시간을 썼던것 같다. 다음 프로젝트에서는 SR 단계에서 좀 더 세부적으로 color 값을 정하고 개발을 진행하는 것도 좋을 것 같다.
Author And Source
이 문제에 관하여(Project Shall-We-Health #4-2 다크 모드/라이트 모드 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@bbaa3218/Project-Shall-We-Health-4-2-다크-모드라이트-모드-구현저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)