기능 구현 - 다크모드

치맨·2023년 6월 25일
1

기능구현

목록 보기
3/9
post-thumbnail

목차


Javascript로 다크모드 구현하기

  • Vanilla Js로 다크모드를 구현 해보겠습니다. 우선 클래스를 사용 해본적이 별로 없기 때문에 클래스를 사용해서 구현해봤습니다.

  • prefers-color-scheme를 사용해서 브라우저 설정에 따라 자동으로 다크모드를 감지하므로 사용자의 환경을 잘 반영할 수 있는 장점은 있지만, 모든 브라우저에서 지원되는 것은 아니며, 구형 브라우저에서는 동작하지 않을 수 있는 단점이 존재하기 때문에 이것으로 구현하지 않았습니다.

  • setAttribute 메서드를 사용하여 최상단 컴포넌트(App 컴포넌트)에 dark 또는 light 속성 값을 추가하는 방식으로 다크모드를 구현했습니다. 사용자의 환경을 자동으로 감지하지 않는 단점이 있지만, 사용자가 직접 버튼을 클릭하여 다크모드를 변경하는 방식이 더 좋다고 판단하여 prefers-color-scheme 방식보다는 setAttribute를 사용했습니다. 이러한 방식으로 다크모드를 구현하면 사용자가 직접 제어할 수 있으며, 브라우저 설정에 의존하지 않기 때문에 호환성 문제도 최소화됩니다.

  1. App.js 파일의 constructor에 DarkModeToggle 클래스 인스턴스를 만들어줍니다.
class App {
  $target = null;

  constructor($target) {
    this.$target = $target;

    this.darkModeToggle = new DarkModeToggle({
      $target,
    });
  }
}

  1. index.js파일에서 DarkModeToggle.js 파일을 script로 추가해줍니다. 참고로 main.js파일은 App클래스를 생성해주는 파일입니다.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <link rel="stylesheet" href="src/style.css" />
    <title>Cat Search</title>
  </head>
  <body>
    <div id="App"></div>
    <script src="src/DarkModeToggle.js"></script>
    <script src="src/App.js"></script>
    <script src="src/main.js"></script>
  </body>
</html>

  1. DarkModeToggle 클래스를 작성 해줍니다.

    • createElement를 사용해 input을 만들어줍니다.

    • 클래스 내부에서 사용할 수 있도록 this.$darkModeBtn에 연결해줍니다.

    • input의 type을 checkbox로 추가 해줍니다.

    • $target을 통해 DOM에 appendChild를 통해 추가해줍니다.

    • change Event를 통해 check될때, check되지 않을때 color-mode 속성으로 'dark', 'light'를 지정해서 다크모드를 구현합니다.
      하단에 color-mode가 바뀌는걸 볼 수 있습니다.

class DarkModeToggle {
  isDarkMode = null;

  constructor({ $target }) {
    const $darkModeBtn = document.createElement('input');
    this.$darkModeBtn = $darkModeBtn;
    this.$darkModeBtn.type = 'checkbox';

    this.$darkModeBtn.className = 'DarkModeBtn';
    $target.appendChild($darkModeBtn);

    this.$darkModeBtn.addEventListener('change', (e) => {
      this.setColorMode(e.target.checked);
    });

    // 업데이트
    this.initialColorMode();
  }

  initialColorMode() {
    this.$darkModeBtn.checked = this.isDarkMode;
    this.setColorMode(this.isDarkMode);
  }

  setColorMode(isDarkMode) {
    document.documentElement.setAttribute('color-mode', isDarkMode ? 'dark' : 'light');
  }
  render() {}
}

  1. 마지막으로 color-mode가 dark인 경우, light인 경우에 따라 css를 변경 해주면 됩니다.
:root[color-mode='dark'] {
  --background: #000;
  --textColor: white;
}

:root[color-mode='light'] {
  --background: white;
  --textColor: #000;
}

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

React+ typescript로 다크모드 구현하기

  1. styled-components의 Themprovider를 활용하여 기능을 구현 해보겠습니다.
  1. 우선 버튼을 통해 다크모드를 구현한다고 가정했을때 App.tsx파일에 버튼을 만들어 주고 버튼의 클릭에 따라 상태값을 true/false로 변경 시켜줍니다.
// App.tsx

import { useState } from 'react';
import styled from 'styled-components';

const DarkModeBtn = styled.button`
원하는 스타일대로 작성
`;

function App() {
  const [BlackAndWhiteBtn, setBlackAndWhiteBtn] = useState(true);

  const togleBtn = () => {
    setBlackAndWhiteBtn((prev) => !prev);
  };
  
  return (
    <>
      <DarkModeBtn onClick={togleBtn}>다크모드</DarkModeBtn>
    </>
  );
}

export default App;

  1. styled.d 파일을 생성해서 다크모드인경우, 아닌경우에 따라 색상을 담을 객체의 내용들의 type을 지정해줍니다.

// styled.d.ts

import 'styled-components';

declare module 'styled-components' {
  export interface DefaultTheme {
    bgColor: string;
    textColor: string;
    boxShadow: string;
  }

  export interface DarkTheme {
    bgColor: string;
    textColor: string;
    boxShadow: string;
  }
}


  1. theme.ts파일을 만들어 다크모드인 경우, 아닌경우 원하는 변수명에 색상을 담아줍니다.

// theme.ts

import { DefaultTheme, DarkTheme } from 'styled-components';

export const Default: DefaultTheme = {
  bgColor: 'rgba(236, 240, 241,1.0)',
  textColor: '#2c3e50',
  boxShadow: '0px 0px 5px rgb(0, 0, 0, 0.2)',
};

export const Dark: DarkTheme = {
  bgColor: '#2c3e50',
  textColor: 'rgba(236, 240, 241,1.0)',
  boxShadow: '0px 0px 5px rgb(255, 255, 255, 0.2)',
};
  1. App 컴포넌트 최상단에 ThemeProvider로 감싸준 뒤, theme 속성으로 다크모드인 경우와 아닌경우에 따라 다르게 만들어 둔 객체를 추가해 줍니다. 이때 state 값에 따라 다르게 처리해야 하므로 삼항 연산자를 사용해 줍니다.

// App.tsx

import { useState } from 'react';
import GlobalStyle from './GlobalStyle';
import styled, { ThemeProvider } from 'styled-components';
import { Dark, Default } from './theme';

const DarkModeBtn = styled.button`
  border: none;
  padding: 10px;
  position: fixed;
  bottom: 10px;
  right: 10px;
  background-color: inherit;
  border: 1px solid ${(props) => props.theme.textColor};
  border-radius: 20px;
  cursor: pointer;
  color: ${(props) => props.theme.textColor};
`;

function App() {
  const [isDarkMode, setIsDarkMode] = useState(false);

  const togleBtn = () => {
    setIsDarkMode((prev) => !prev);
  };

  return (
    <>
      <ThemeProvider theme={isDarkMode ? Dark : Default}>
        <GlobalStyle />
        <DarkModeBtn onClick={togleBtn}>다크모드</DarkModeBtn>
      </ThemeProvider>
    </>
  );
}

export default App;

  1. 마지막으로 사용하길 원하는곳에서 props.theme.원하는 색상 으로 접근해서 사용하면 됩니다.
  • 저는 버튼의 색상과, body의 배경색상을 바꿔보겠습니다.
const DarkModeBtn = styled.button`
  color: ${(props) => props.theme.textColor};
`;
  
 body{
        background-color: ${(props) => props.theme.bgColor};
    };


기능 구현하면서 느낌점

  • Vanilla JS 클래스형으로 구현한 경우 JavaScript 코드를 직접 작성해야 하고 다크모드를 적용하는 컴포넌트가 늘어나면 관리가 어려울 것 같다는 생각이 듭니다.
    반면에 React의 styled-components를 사용하여 다크모드를 적용하는 컴포넌트가 많아져도 관리 하기 수월할 것 같다는 생각이 드네요.

  • Vanilla Js와 React 2가지 다크모드를 구현하면서 라이브러리의 사용성과 생산성을 다시 한 번 느낄 수 있었습니다. 라이브러리를 활용하면 작업량이 줄어들고 코드의 일관성과 유지보수성을 높일 수 있다는걸 많이 느꼈습니다. 라이브러리 좋아요! 하지만 지금은 배우는 단계이기 때문에 라이브러리 사용 보다는 순수 Vanilla Js로 구현해보며 기본 원리를 배우는데 집중 해야겠습니다.

profile
기본기가 탄탄한 개발자가 되자!

0개의 댓글