#ui/ux, #css, #css-in-js, #darkmode

다크모드의 의의와 웹환경에서의 구현

구글, 애플이 도입한 다크모드

몇 년 전부터 일상 디지털환경에 다크모드란 기능이 자연스럽게 자리 잡았습니다. 정확한 시점을 특정할 수는 없으나 IT대기업들이 다크 모드를 도입하면서 대중들이 해당 개념을 더욱 빨리 받아들였다는 것을 부인하긴 어려울 것 같습니다. 구글은 2018년 안드로이드 9.0(파이)에 다크모드를 도입하였고, 애플은 Mojave MacOS와 iOS 13버전에 기능을 업데이트하였습니다. 이제는 windows, Github, Facebook, Slack 등 다수의 서비스에서 다크모드 기능을 쉽게 찾을 수 있습니다.


다크모드는 왜 필요할까?

어두운 컬러 계열의 배경, 밝은 컬러 계열의 텍스트 UI테마를 다크모드라 일컫습니다.

다크모드의 장점은 다음과 같습니다.

시인성(대상이 눈에 쉽게 보이는 정도)이 높아진다.

화면 전반적으로 밝은 빛이 줄고, 이미지 등의 컨텐츠와의 색 대비가 높아져, 사용자 주변의 조명 확보가 어려운 상황에서도 내용을 더 쉽게 볼 수 있게 해줍니다. 찾고자 하는 글자나 이미지가 더 눈에 잘 띕니다.

눈의 피로가 줄어든다.

케임브릿지 대학교 Silas S. Brown교수의 의견에 따르면 배경색을 어둡게 하면 눈부심으로 인한 눈의 피로가 줄고, 블루라이트로 인한 수면방해도 덜하다는 장점이 있다고 합니다. OLED 디스플레이의 경우 검정색의 경우 픽셀을 끄기 때문에 픽셀이 켜졌을 때 발생하는 픽셀의 깜빡임으로 인한 시각적 피로가 줄어듭니다.

이외에도 유저가 테마를 직접 고른다는 점에서 서비스는 유저의 개인화에 대한 욕구를 충족시켜줄 수 있습니다.


웹 환경에서 구현하기

사용자의 시스템 설정 가져오기: prefers-color-scheme

CSS 미디어쿼리의 속성 중 prefers-color-scheme이라는 속성은 사용자의 시스템이 라이트 / 다크테마를 사용하는지 감지합니다. 이 속성을 통해 별다른 작업 없이도 사용자의 선호 테마를 알 수 있습니다. 이는 처음 서비스에 진입한 유저의 사용경험을 증진시키는데 도움이 될 수 있을 것입니다.

div {
  width: 10rem;
  height: 10rem;
  border: 5px solid gray;
}

/* 다크모드 */

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

/* 라이트모드(둘 중 하나는 default속성으로 설정해줘도 됨) */

@media (prefers-color-scheme: light) {
  div {
    background: white;
    color: black;
  }
}

CSS의 기능인 커스텀 CSS 속성을 이용한다면 속성의 컬러값만 변경함으로써 테마의 변경을 이끌어낼 수도 있습니다.

div {
  width: 10rem;
  height: 10rem;
  border: 5px solid gray;
  background-color: var(--bg-color);
  color: var(--color);
}

/* 다크모드 */

@media (prefers-color-scheme: dark) {
  html {
    --bg-color: black;
    --color: white;
  }
}

/* 라이트모드(둘 중 하나는 default속성으로 설정해줘도 됨) */

@media (prefers-color-scheme: light) {
  html {
    --bg-color: white;
    --color: black;
  }
}

사용자가 테마를 선택한다: 루트 요소에 attribute 설정

prefers-color-scheme 속성을 이용하게 되면 유저가 해당 서비스의 테마를 임의로 조정할 수 없다는 단점이 있습니다. 그래서 기본적으로 prefers-color-scheme 속성을 사용함과 더불어 유저가 UI 내 토글 등을 이용해 테마를 선택하게 하는 것이 더 나은 UX를 체험할 수 있게할 수 있을 것입니다. 해당 설정값을 유저로부터 전달받는다면, localStorage나 db에 저장하고 추후 유저가 서비스에 재진입시 해당 값을 불러와 테마를 불러올 수 있습니다.

div {
  width: 10rem;
  height: 10rem;
  border: 5px solid gray;
  background-color: var(--bg-color);
  color: var(--color);
}

/* 다크모드 */

html[data-theme='dark'] {
  --bg-color: black;
  --color: white;
}

/* 라이트모드(둘 중 하나는 default속성으로 설정해줘도 됨) */

html[data-theme='light'] {
  --bg-color: beige;
  --color: black;
}

CSS 커스텀 속성으로 웹앱 내부 요소들의 모든 스타일을 커버하기 어렵다 여겨지는 경우 CSS의 특정성을 이용해 스타일을 입힐 수도 있을 것입니다.

div {
  width: 10rem;
  height: 10rem;
  border: 5px solid gray;
  background-color: white;
  color: black;
}

/* 다크모드 */

html[data-theme='dark'] div {
  background-color: black;
  color: white;
}

/* 라이트모드(둘 중 하나는 default속성으로 설정해줘도 됨) */

html[data-theme='light'] div {
  background-color: beige;
  color: black;
}

CSS-in-JS: styled-components 예시로부터

요즘의 웹개발환경에서는 CSS-in-JS를 활용한 스타일 방식도 활용되고 있습니다. CSS-in-JS는 어떤 방식으로 테마를 설정할까요? 가장 널리 사용되고 있는 CSS-in-JS 라이브러리 중 하나인 styled-components의 예시를 보고 테마 적용 컨셉을 알아보겠습니다.

리액트용 컴포넌트 스타일링 툴인 styled-components는 테마 CSS속성을 주입하기 위해 <ThemeProvider>라는 wrapper컴포넌트를 사용합니다. 이 컴포넌트는 리액트의 Context API를 이용해서 자식 컴포넌트들에게 테마CSS속성을 전달해줍니다. 때문에 자식컴포넌트로 갖고만 있다면 테마를 주입하고, 변경할 수 있습니다.

// 버튼을 정의합니다. props.theme을 받아와 main컬러 값을 적용해주고 있습니다.
const Button = styled.button`
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border-radius: 3px;

  color: ${props => props.theme.main};
  border: 2px solid ${props => props.theme.main};
`;

// 테마 객체를 선언해 프로퍼티값으로 테마CSS속성을 정의해줍니다
const theme = {
  main: 'mediumseagreen',
};

render(
  <div>
    <Button>Normal</Button>

    <ThemeProvider theme={theme}>
      <Button>Themed</Button>
    </ThemeProvider>
  </div>,
);

마치며

왜 다크모드가 현 IT서비스들에서 유행을 하고 있는지, 어떻게 다크모드를 적용할 수 있는지를 알아보았습니다. 오늘 살펴본 방법들을 꿰뚫는 중심 컨셉은 가장 최상단에서 테마에 대한 정보를 갖고 있고, 이를 하위의 요소들에게 전파하는 것입니다. 최상단의 요소만 정보를 바꿔준다면, 하위의 요소들은 별도로 설정할 필요없이 테마가 바뀌게 됩니다. 이를 파악하고 있다면 다른 테마를 적용하는 기술이 등장했을 때도 해당 지식을 기반으로 대응할 수 있을 것입니다.

Reference