본문 바로가기
Javascript

Dark Mode를 만들어 보자(ft. classList.add)

by 즐코딩 2023. 1. 25.
반응형

Dark Mode를 만들어 보자



웹사이트를 서핑하다보면, Dark Mode라는 것들이 눈에 많이 띕니다. 물론 브라우저나 VSCode 같은 IDE에도 Dark Mode가 존재합니다. Windows에도 다크 모드가 존재하죠.

다크 모드를 세팅해 놓으면 밋밋했던 화면보다, 뭔가 '어둠의 다크한' 느낌이 들면서 좀 더 프로페셔널한 느낌을 가져다주는 것도 사실입니다. 기분 탓인가?

사실 다크모드는 '에너지 절약' 차원에서 아이디어가 나온 것이겠죠? 아무래도 모니터는 RGB 광선을 모두 쏘아주어야 White Color(흰색)가 만들어지니까요. 검은 색은 RGB 광선을 쏘지 않는 상태이니 아무래도 전기 등의 에너지도 절약이 될 것입니다.

또한 밤 늦은 시간에, 화면이 너무 밝은 것도 눈이 불편하기도 하구요. 여러 모로 Dark Mode는 이래저래 사용자들에게 각광을 받는 시대가 이미 되어버린 것 같습니다.


Dark 모드는 CSS를 미리 만들어두고 classList.add로 클래스를 붙여주는 것

다크 모드는 가만히 살펴보면 결국 CSS로 어두운 느낌의 스타일링을 미리 만들어 두었다가, [Dark Mode] 버튼을 클릭할 때 다크 모드 적용이 필요한 Elements들의 클래스에 해당 클래스를 추가해주는 것이 뽀인트입니다.


아직은 무슨 말인지 이해가 잘 되지 않죠? 간단하게 예제를 만들어서 살펴보기로 해봅시다.


예제 코드 HTML 탬플릿


부트스트랩 사용을 위해 부트스트랩 CSS를 <head>에 불러왔습니다.

<head>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />
</head>

<body>
<div class="container mt-5">
  <button class="btn btn-dark">Dark Mode</button>
  <h1 id="title" class="mt-5">다크 모드 만들기</h1>
  <div class="row">
    <div class="col-md-6">
      <div class="card" style="width: 18rem">
        <img src="1.jpg" class="card-img-top" alt="..." />
        <div class="card-body">
          <h5 class="card-title">Card title</h5>
          <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
          <a href="#" class="btn btn-primary">Go somewhere</a>
        </div>
      </div>
    </div>
    <div class="col-md-6">
      <div class="card" style="width: 18rem">
        <img src="2.jpg" class="card-img-top" alt="..." />
        <div class="card-body">
          <h5 class="card-title">Card title</h5>
          <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
          <a href="#" class="btn btn-primary">Go somewhere</a>
        </div>
      </div>
    </div>
  </div>
</div>
</body>


브라우저에서 실행을 해보면 아래와 같이 표현됩니다.

Light-Mode-상태의-HTML-템플릿
Light Mode 상태의 HTML 템플릿


CSS로 Dark Mode를 스타일링


다크 모드라면 일단 배경이 어두운 색이어야 겠죠? 다크 모드 따위는 생각하지 말고, 그냥 평소의 CSS 스타일링 방식으로 Body의 배경을 어두운 색(#333333)으로 만들어 보도록 합니다.

<body class="dark"> <!-- body의 class에 dark를 추가하고 -->

<div class="card-body dark"> <!-- card-body의 div class에도 dark를 추가합니다. 2군데 -->


<style>
.dark { background-color: #333333; color: white;} /* 배경색은 어둡게, 글자색은 밝게 CSS 스타일링 적용 */
</style>


목적하는 Dark Mode 결과가 적용이 되었습니다.

다크-모드로-변경된-모습
다크 모드로 변경된 모습


그러면, 이제 Javascript를 이용해서 dark라는 class 명을 떼었다 붙였다 하면 되겠네요?


Javascript로 class 추가하기 - classList.add()


웹문서를 조작하려면 당연히 자바스트립트를 떠올려야 겠죠?

일단, 다크모드 클래스 적용이 필요한 엘리먼트들을 한 번에 모두 적용하기 위해서 change라는 클래스를 줍니다.

<body class="change">

<div class="card-body change">
.
.
<div class="card-body change">


위 예제들은 아래의 Javascrpt 코드로 조작을 해보면,

document.querySelector(".change").classList.add("dark");
카드의-본문-배경-색상도-변경이-필요해보입니다.
카드의 본문 배경 색상도 변경이 필요해보입니다.


어라? body의 배경만 어둡게 변경되었네요? 왜 그럴까요?

querySelector를 사용해서 그렇습니다. 이건 1개만 조작해주니까요. change 클래스가 적용된 모든 엘리먼트들을 변경 조작해주려면 querySelectorAll을 사용해줘야 합니다.(+ 그리고 인덱싱이 필요하죠)

<script>
  document.querySelectorAll(".change")[0].classList.add("dark");
  document.querySelectorAll(".change")[1].classList.add("dark");
  document.querySelectorAll(".change")[2].classList.add("dark");
</script>


원하던 결과가 나왔습니다.

카드-본문-배경-색상도-어둡게-변경이-된-모습
카드 본문 배경 색상도 어둡게 변경이 된 모습


그런데 뭔가 좀 코드가 반복되는 게 불편하지 않은가요?

document.querySelectorAll(".change")[0].classList.add("dark");
document.querySelectorAll(".change")[1].classList.add("dark");
document.querySelectorAll(".change")[2].classList.add("dark");


조작할 대상이 수 십 개, 수 백 개 라면요? 이 라인을 수백개 써줘야겠네요?



querySelectorAll은 반복문과 함께 사용해서 업그레이드



querySelectorAll은 반복문을 사용해서 훨씬 더 편리하게 사용할 수 있습니다.

const elem = document.querySelectorAll(".change");   //변수에 담아 코드를 줄이고, 가독성 좋게

for (let i = 0; i < elem.length; i++) {           // .length를 사용(실무에서 매우 많이 사용하는 방법)
  document.querySelectorAll(".change")[i].classList.add("dark");
}


.length로 배열의 길이를 가져오는 것은 실무에서 매우 많이 사용하는 방식입니다. 완전 편하죠?
그 다음은 for 반복문을 돌려서, dark 클래스를 추가해주게 됩니다.

바닐라 자바스크립트(=쌩 자바스크립트)는 이렇게 코드가 좀 길어질 수 있는 성질이 있습니다.


jQuery로 코드 길이 줄여보기


이 즈음에서 jQeury를 사용하게 되면 코드 길이가 훅~ 줄어들게 됩니다.(각자 개인의 취향)
단점이라면, jQuery만의 명령어를 알아야 한다는 것이죠. 초보 때는 이게 좀 헷갈릴 수 있습니다.
저도 쌩 자바스크립트 명령어와 제이쿼리 명령어를 서로 혼동하고 그랬었습니다. 막 이래.

그래서, 다소 불편하긴 하더라도 바닐라 자바스트립트로 우선 공부하는 것이 권장된다고 생각합니다.
한 놈만 패는 게 초보 시절에는 효율적일 수 있으니까요.

아무튼 jQuery로 동일한 코드를 짜 보면 아래와 같습니다.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>  //jQuey 불러오기

<script>
  $(".change").addClass("dark");  
</script>


정말 매우 간단하지 않은가요? jQuery에서는 $로 잡아온 녀석들에 대해 반복문 같은 게 필요 없습니다.
이래서 jQuery를 사용하면 편리하긴 한데, addClass()라는 제이쿼리용 함수를 따로 또 알아야 하는 것이죠.

뭐.. 각자 선택의 영역입니다.



마지막 단계, 버튼에 Dark Mode 기능 구현하기



이제 다크 모드를 만들기 위한 테스트를 모두 진행했으니, 상단에 만들어 놓은 버튼에 해당 기능을 구현하기만 하면 목적하는 바가 달성되겠습니다. 버튼에는 addEventListener를 사용해보도록 합시다.

<script>
  document.querySelector(".btn").addEventListener("click", function () {
  const elem = document.querySelectorAll(".change");
  for (let i = 0; i < elem.length; i++) {
    document.querySelectorAll(".change")[i].classList.add("dark");
    }
  });
</script>


버튼을 클릭해보면, 이벤트 리스너가 감지하고 있다가 click 이벤트가 발생할 때, 콜백 함수를 실행해주게 됩니다.
콜백 함수 안에는 앞에서 테스트 해보았던 코드들이 들어 있습니다. 단계를 나누어 코딩을 진행해보니, 생각보다 쉽게 해결된다는 느낌이 생기지 않나요?



마치며 + 심화학습(Further Study)



아래는, 심화 학습을 위해 버튼을 한번 누르면 다크 모드로, 다시 한번 누르면 라이트 모드로 변경되는 코드를 구성해보았습니다. 코드만 두 배로 길어져서 복잡해 보일 뿐 사실 크게 달라진 점은 없습니다.

코드를 살펴보면서 이리 저리 수정해보면서 테스트를 진행해보면, 조금씩 나도 모르는 코딩 근육이 자라날 것이라고 생각합니다. 코딩은 백문이 불여일견, 백견이 불여일행입니다. 꼭 스스로 코드를 다뤄보세요.

<script>
  let count = 0;
  document.querySelector(".btn").addEventListener("click", function () {
    if (count % 2 == 0) {
      document.querySelectorAll(".btn")[0].innerHTML = "Light Mode";
      const elem = document.querySelectorAll(".change");
      for (let i = 0; i < elem.length; i++) {
        document.querySelectorAll(".change")[i].classList.add("dark");
      }
      count = count + 1;
    } else {
      document.querySelectorAll(".btn")[0].innerHTML = "Dark Mode";
      const elem = document.querySelectorAll(".change");
      for (let i = 0; i < elem.length; i++) {
        document.querySelectorAll(".change")[i].classList.remove("dark");
      }
      count = count + 1;
    }
  });
</script>
다크모드,-라이트모드-변경-버튼까지-최종-완성된-모습
다크 모드, 라이트 모드 변경 버튼까지 최종 완성된 모습


완벽하게, Dark Mode ↔ Light Mode 간 변환 기능이 완성이 된 것 같습니다.



즐거운 코딩생활, 즐코딩
KINcoding

반응형

댓글