이 글에서는 @-ft/mode-next를 활용해 Next.js 프로젝트에 다크모드를 적용하는 방법을 다룹니다.
기본적인 다크모드 판별/적용 방법
@media (prefers-color-scheme: dark) CSS 미디어 쿼리를 통해 다크모드를 판별할 수 있습니다.
window.matchMedia 함수를 활용하면 언제 다크모드를 적용하고 해제해야 할지 알 수 있습니다.
하지만 시스템 설정이 다크모드라도, 어떤 사이트에서는 라이트 모드로 보고 싶을 수도 있습니다.
그래서 많은 서비스에서는 다크모드 관련 설정 세가지를 제공합니다. (앞으로 이 셋을 모드라고 하겠습니다.)
•
시스템 설정을 따라가도록
•
시스템 설정과 상관 없이 다크모드
•
시스템 설정과 상관 없이 라이트모드
tailwindcss 웹사이트 (예시)
이런 경우, CSS의 미디어 쿼리에만 의존할 수 없습니다.
자바스크립트로 다크모드를 변경할 수 있어야 하기 때문입니다.
그래서 다크모드를 적용할 때 상위에 특정 클래스(예: dark)가 있는지 확인하는 식으로 적용합니다.
.my-class {
/* 기본: 라이트모드 */
background: #fafafa;
}
.dark .my-class {
/* .dark *: 다크모드 */
background: #000000;
}
CSS
복사
다크모드를 구현하려면…
다크모드를 구현하려면 우선 시스템 설정을 따를 때에는 시스템 설정 변경을 감지할 수 있어야 합니다.
그리고 사용자가 선택한 모드와 시스템 설정에 따라 다크모드 테마를 적용할지 결정하고,
이에 따라 DOM의 상위 노드(대부분 html)에 다크모드 테마 적용 여부를 판별할 클래스를 주입합니다.
그리고 모드를 변경할 때마다 쿠키 등에 저장했다가, 페이지를 이동하거나 새로고침하면 불러봐야 합니다.
그냥 하면 되는, 어려울 건 없는 작업이지만 모든 프로젝트에서 매번 하기는 귀찮은 작업입니다.
다행히도 이 모든 작업을 쉽게 해 주는 라이브러리가 있습니다! 제가 만들었습니다ㅜ
바로 @-ft/mode라는 패키지입니다.
하지만 이 패키지를 바로 사용하면 SSR 문제와 hydration 이전에 테마가 적용되지 않는 문제가 있습니다.
@-ft/mode-next 패키지
@-ft/mode 패키지에서 위 문제를 해결한 게 @-ft/mode-next 패키지입니다!
사용 방법도 간단합니다.
{
"variableName": "__theme_mode",
"persist": {
"type": "cookie",
"key": "THEME_MODE",
}
}
JSON
복사
/public/mode.js 파일을 @-ft/mode-codegen 패키지를 활용해 생성하고 나서
import { ModeContextProvider } from '@-ft/mode-next';
export default function RootLayout({ children }: PropsWithChildren) {
const mode = cookies().get('THEME_MODE');
return (
<html lang="en" className={mode?.value} suppressHydrationWarning>
<head>
<script src="/mode.js" />
</head>
<body>
<ModeContextProvider variableName="__theme_mode">
{children}
</ModeContextProvider>
</body>
</html>
);
}
JavaScript
복사
/src/app/layout.tsx 레이아웃에서 /mode.js를 불러오게 만들고,
(선택적으로) 적절한 클래스를 주입한 후 hydration warning을 suppress하면
'use client';
import { ModeContext } from '@-ft/mode-next';
function ModeBar() {
const { mode, setMode } = useContext(ModeContext);
return (
<Bar>
Current theme mode is {mode}.
<Select
onChange={useCallback((mode) => setMode(mode), [setMode])}
>
{['system', 'light', 'dark']}
</Select>
</Bar>
)
}
JavaScript
복사
다크모드를 이토록 쉽게 바로 사용할 수 있습니다!