개발공부/웹

CSS에서 다크모드 설정 방법 (feat. prefers-color-scheme)

개발자 찐빵이 2023. 1. 26. 22:48
728x90
반응형

최근에 많이 사용되는 다크모드, 라이트모드를 구현해 보면서 처음 알게 된 내용을 정리해보려고 한다.

1. OS 설정에 맞춰 모드 변경하는 방법 : prefers-color-scheme

prefers-color-scheme 미디어 쿼리는 OS에서 설정된 라이트/다크 모드를 감지하여
자동으로 라이트, 다크 모드 스타일을 적용하는 기능이다.

일반식으로 쓰면 아래처럼 표현할 수 있다.

@media (prefers-color-scheme: 모드) {
  /* 해당 모드에 적용할 스타일 */
}

다크모드 스타일 설정 예시

@media (prefers-color-scheme: dark) {
  body {
    background-color: var(--background-color);
    color: var(--text-color);
  }
}

라이트모드 스타일 설정 예시

@media (prefers-color-scheme: light) {
  body {
    background-color: var(--background-color);
    color: var(--text-color);
  }
}

웹 사이트 규모가 커지면 다크모드, 라이트모드 지원을 위한 스타일이 복잡해진다.
더 쉬운 모드 스타일을 위해 CSS 변수를 사용할 수 있다.

:root {
  --loading-indicator-color: #ff9d3f;
  --loading-indicator-background: #efebe9;
  --black: #1b1b1b;
  --white: #fff3e0;
}

@media (prefers-color-scheme: dark) {
  body {
    background-color: var(--black);
    color: var(--white);
  }
}

@media (prefers-color-schemeL: light) {
  body {
    background-color: var(--white);
    color: var(--black);
  }
}

2. 웹 페이지 내 토글 버튼을 추가하여 변경하는 방법

다크모드를 설정할 수 있는 토글 버튼 또는 체크박스를 추가하여 웹 내부에서 자체적으로 제어할 수 있는 방법이다.
만들어 둔 다크모드 설정 체크박스에 클릭 이벤트를 추가하여 body.dataset을 변경하는 방식으로 구현해봤다.

Html

<body data-theme="light-mode">
    <label class="darkmode_checkbox">
        <input type="checkbox" class="darkmode_input" />
        <span class="darkmode_text">다크모드 여부</span>
    </label>
</body>

HTML에서 data-* 형식의 속성은 개발자가 정의한 데이터를 저장하는 데 사용된다.
나는 테마를 저장해 주기 위해 data-theme라는 값을 만들고, 기본 값으로 light-mode를 설정하였다.

JavaScript

darkmode_input.addEventListener('click', (event) => {
    if (event.target.checked) {
        document.body.dataset.theme = 'dark-mode';
    } else {
        document.body.dataset.theme = 'light-mode';
    }
});

다크모드 체크박스에 클릭 이벤트를 걸어둔다.
체크되었다면 다크모드를, 아니라면 라이트 모드를 설정한다.

data 값을 자바스크립트에서 사용하려면 dataset.* 형식으로 접근해야 한다.

CSS

body[data-theme='light-mode'] {
  --background-color: #fff3e0;
  --text-color: #1b1b1b;
  --button-color: #ffe97d;
}

body[data-theme='dark-mode'] {
  --background-color: #1b1b1b;
  --text-color: #fff3e0;
  --button-color: #ffe97d;
}

body {
  background-color: var(--background-color);
  color: var(--text-color);
}

이제 CSS에서 테마 값에 따른 변수를 설정하고 바디에 적용해 주면 끝!

3. 위 둘을 동시에 적용하려면?

1번, 2번을 동시에 사용할 때 OS 모드에 따라 변경도 되고, 웹 내부에서도 변경이 될 줄 알았다.
그런데.. 그렇게 되지 않았다!

웹 체크박스에 따른 설정이 아예 먹통이 되어버렸다.ㅠㅠ

그럼 어떻게 해야 할까?

1번의 css에서 설정한 미디어 쿼리를 제거하고, 자바스크립트에서 설정하는 방법으로 구현할 수 있었다.

const mediaQuery = '(prefers-color-scheme: dark)';
setTheme(window.matchMedia(mediaQuery)); // 초기화
window.matchMedia(mediaQuery).addEventListener('change', setTheme);

function setTheme(mediaQueryList) {
  document.body.dataset.theme = mediaQueryList.matches ? 'dark-mode' : 'light-mode';
}

웹이 실행될 때 테마를 초기화 해준 다음, OS의 모드가 변경되면 dataset.theme 값도 변경되도록 수정해 주었다.

참고자료

data-* 란 무엇일까?
미디어 쿼리 리스트

반응형

'개발공부 > ' 카테고리의 다른 글

시맨틱 마크업, 왜 필요할까?  (0) 2023.01.28
구글 폰트 내 웹 사이트에 적용하는 방법  (0) 2023.01.26
[React] memo와 react hook  (0) 2022.04.23
React의 pureCompoent 특징  (0) 2022.04.23
[React] Refs  (0) 2022.04.21