DogKaeBi
[Next.js] tailwind 다크모드

[Next.js] tailwind 다크모드

tailwindcss로 다크모드 설정하고, 제어 버튼으로 라이트모드/다크모드 전환하기. 디바이스 모드 확인하여 첫 방문 모드 설정하기.

코딩

목차

  • 1. tailwidncss 다크모드
  • 1.1. body class 추가
  • 1.2. html 테스트용 class 추가
  • 2. 다크모드 controller
  • 2.1. DarkmodeBtn
  • 2.2. 디바이스 모드 감지
  • 3. 완료

사이트 콘텐츠는 조금 정리가 되었다.
이제 천천히 분류에 맞게 내용을 추가하면된다.

그래서 요즘
사이트 기능이나 디자인을 조금씩 수정하면서
어떻게 해야 더 좋은 UI가 될지 고민이 되기 시작했다.



tailwidncss 다크모드

요즘은 대부분 사이트에 있는 다크모드.
처음에 사이트를 만들 때,
"우선 만들고 고치자" 마인드이어서,
css코드에 색상 가이드를 전혀하지 않았다.

시작하려하니 조금 막막했으나,
우선 tailwind에서 찾아보기로 했다.
[tailwindcss 공식문]

아주 간단하게,
클라스네임에 dark:만 사용하면
다크 모드를 뜻한다.

그러면
body 혹 html의 class명에 "dark"가 있으면
dark: 뒤에 스타일이 적용된다.


body class 추가

전체적으로 수정할 수 있도록,
아예 body태그에 dark:을 추가했다.
나는 전체를 layout.js로 틀을 만들어서,
Home의 layout.js 를 수정했다.

// .\app\(route)\layout.js

export default function RootLayout({ children }) {
  return (
    <html lang="ko" className="dark">
      <head>...</head>
      <body className={inter.className + '  bg-white dark:bg-black dark:text-white'}>...</body>
    </html>
  );
}

위처럼
body의 className bg-white 뒤에
dark:bg-black dark:text-white를 추가했다.
(다크모드에 검은 배경 및 하얀 텍스트)


html 테스트용 class 추가

위처럼 테스트를 위해
html의 className은 dark를 추가했다.

다른 색상을 사용한 텍스트 혹 요소는
하나씩 찾아보면 안보이는지 확있하고,
필요한 부분은 다크모드 class를 추가했다.



다크모드 controller

css는 완료되었다.
이제 html의 class에
dark를 추가/삭제하는 제어장치가 필요하다.

이벤트를 사용해야 하기 때문에,
use client를 사용해야 한다.
그래서 별도의 컴포넌트를 만들었다.


DarkmodeBtn

방식은 간단하다.
버튼을 만들고,
버튼이 클릭되면
html태그의 클래스를 추가/삭제한다.

// .\app\components\DarkmodeBtn.js

'use client';

const DarkmodeBtn = () => {
  return <button onClick={handleClick}>🌗</button>;

  function handleClick() {
    document.querySelector('html').className == '' ? (document.querySelector('html').className = 'dark') : (document.querySelector('html').className = '');
  }
};

export default DarkmodeBtn;

예시처럼,
button을 return하는 컴포넌트이다.
button이 onClick되면 handleClick을 호출한다.

handleClick은
document.querySelector('html').className 으로 현재 클라스명을 확인하고,
값이 없으면 dark를 추가하고,
값이 dark이면 "빈칸"으로 변경한다.

렌더링을 고려해야 하나 했지만 그냥 잘 작동된다.
생각해보니 css는 원래 브라우저가 처리해서
아마 class명이 변경되면
스타일도 자동으로 변경시키는 것 같다.


디바이스 모드 감지

처음 방문하면 무조건 라이트모드이다.

디바이스가 다크/라이트인지 확인하고
처음 방문할 때, 디바이스를 기준으로 하는 기능을 추가했다.

// .\app\components\DarkmodeBtn.js

'use client';
import { useEffect } from 'react';

const DarkmodeBtn = () => {
  function handleClick() {
    document.querySelector('html').className == '' ? (document.querySelector('html').className = 'dark') : (document.querySelector('html').className = '');
  }

  useEffect(() => {
    if (window.matchMedia('(prefers-color-scheme:dark)').matches) {
      document.querySelector('html').className = 'dark';
    }
  }, []);

  return <button onClick={handleClick}>🌗</button>;
};

export default DarkmodeBtn;

react의 useEffect를 사용했다.
의존으로 빈 배열을 []을 사용해서
처음 랜더링될 때만 작동한다.

window.matchMedia('(prefers-color-scheme:dark)').matches
으로 디바이스가 'dark'인지 확인하고,
다크모드이면 html의 class에 'dark'를 추가한다.



완료

이렇게 다크모드를 완료했다.
결론은

  1. tailwindcss를 사용해서
    다크모드일 때 변화가 필요한 부분에
    dark:을 추가해서 스타일을 만든다.

  2. 다크모드 제어 버튼을 만든다.
    querySelector로 html태그를 확인하고,
    class에 'dark'를 추가/삭제한다.

  3. 추가로 window.matchMedia를 이용해서
    디바이스가 다크/라이트모드를 확인하고
    useEffect를 사용해서
    처음 렌더링 시, 디바이스 모드 기준으로 사이트 모드를 정하게 했다.