이야기 정리

새로고침을 해도 유지되는 다크모드 - localStorage() 본문

개발공부/JavaScrit

새로고침을 해도 유지되는 다크모드 - localStorage()

jinhistory 2023. 2. 1. 12:47

얼마전 트위터에서 한 유저가 공유한 코드가 있었다.

새로고침을 해도 다크 모드가 유지되는 코드였는데, 이 코드에 사용된 것이 localStorage였다. (해당 유저의 코드는 최하단 참조란에 링크를 넣었다.)

localStorage을 사용하는 방법과 이를 이용해 다크 모드를 만드는 방법 두가지에 대해 알아보려 한다.

 

다음은 완성된 코드다.

 

See the Pen Dark Mode by beren-105 (@beren-105) on CodePen.


localStorage란?
  • 브라우저의 key-value 값을 Storage에 저장할 수 있으며, 저장된 데이터는 세션간 공유된다.
  • 즉, 세션이 바뀌어도 저장된 데이터 값은 유지된다. 같은 컴퓨터에서 같은 브라우저를 사용하는 이상 브라우저에 저장되는 것이다.
  • 브라우저에 저장되는 값이기 때문에 같은 컴퓨터여도 다른 브라우저면 저장되지 않는다.

 

// key에 value 쓰기
localStorage.setItem("key", value);

// key에서 value 읽기
localStorage.getItem("key");

// key의 value 삭제하기
localStorage.removeItem("key");

// 모든 key value 삭제
localStorage.clear();

// 저장된 key 개수
localStorage.length;

// index로 key의 값 찾아내기
localStorage.key(index);

단점 ! localStorage는 문자열 데이터 밖에 저장할 수 없다 !

  • localStorage는 숫자열을 입력해도 문자열로 나온다.
  • 때문에 객체형 데이터를 저장 시 문제가 생길 수 있다.

 

해결방법
  • JSON 사용하기
// 저장할 객체와 배열
const foo = {bar: 'bar', baz: 1}
const arr = ['foo', 'bar', 'baz']

// 객체와 배열을 JSON으로 변환하기
const fooJSON = JSON.stringify(foo)
const arrJSON = JSON.stringify(arr)

// localStorage에 작성
window.localStorage.setItem('foo', fooJSON)
window.localStorage.setItem('arr', arrJSON)

// 값 읽기
const fooGetItem = window.localStorage.getItem('foo') //{"bar":"bar","baz":1}
const arrGetItem = window.localStorage.getItem('arr') //["foo","bar","baz"]

// 문자열을 다시 객체와 배열로 반환하기
const fooFinal = JSON.parse(fooGetItem)
const arrFinal = JSON.parse(arrGetItem)

console.log(fooFinal) //{bar: 'bar', baz: 1}
console.log(arrFinal) //['foo', 'bar', 'baz']

 

위 과정을 간단하게 하면 다음과 같다.

localStorage.setItem('foo', JSON.stringify({bar: 'bar', baz: 1}))
const foo1 = JSON.parse(localStorage.getItem('foo'))

console.log(foo1)

 

 

- 다크모드 구현하기


구현방법

다크모드를 구현하는 방법에는 크게 두가지가 있다. dataset 혹은 미디어 쿼리를 이용하는 방법이다.

미디어 쿼리 방식을 사용할 시, 웹 브라우저의 다크모드나 운영체제의 다크모드와 연동되기 때문에 유저가 선택할 수 없다. 결국 유저가 선택할 수 있게 만들려면 dataset과 동일한 방법으로 자바스크립트를 만들어야하기 때문에 잘 사용하지 않는다.

때문에 미디어 쿼리가 아닌 dataset을 사용해 만들 예정이다.

 

1. style : dataset  작성하기
:root[data-theme='dark'] {
    --background-color: rgb(68 64 60);
    --card-color: rgb(28 25 23);
    --text-color: rgb(245 245 244);
}

:root[data-theme='light'] {
    --background-color: rgb(255 237 213);
    --card-color: #fff;
    --text-color: rgb(68 64 60);
}
  • style에서 :root를 사용하면 간단하게 구현할 수 있다.

 

2. script : 다크모드 클릭 이벤트
  • localStorage를 사용하기 전, 버튼 이벤트를 만들어준다.
  • setAttribute를 이용하면 root에서 만든 설정을 간단하게 적용할 수 있다.
const button = document.querySelector('button')
let status = false

// 버튼클릭
button.addEventListener('click', () => {
    if (status === false) {
        clickDarkMode()
    } else if (status === true) {
        clickLightMode()
    }
})

// 다크/라이트 전환이벤트
function clickDarkMode() {
    button.innerText='Light'
    document.documentElement.setAttribute('data-theme', 'dark')
    status = true
}
function clickLightMode() {
    button.innerText='Dark'
    document.documentElement.setAttribute('data-theme', 'light')
    status = false
}

 

3. script : 사용자의 테마 읽기

이제 localStorage를 사용할 차례다.

const userTheme = localStorage.getItem('theme')

// 처음 이용객의 테마를 읽음
document.addEventListener('DOMContentLoaded', () => {
    if (userTheme === 'dark') {
        clickDarkMode()
    } else if (userTheme === 'light') {
        clickLightMode()
    }
})

 

마지막으로 다크/라이트 전환 이벤트로 사용한 함수에 전환됐을 시 테마를 바꿔주는 코드를 한줄씩 넣어주면 완성이다.

다음은 완성된 최종 코드다.

const button = document.querySelector('button')
const userTheme = localStorage.getItem('theme')
let status = false

// 처음 이용객의 테마를 읽음
document.addEventListener('DOMContentLoaded', () => {
    if (userTheme === 'dark') {
        clickDarkMode()
    } else if (userTheme === 'light') {
        clickLightMode()
    }
})

// 버튼클릭
button.addEventListener('click', () => {
    if (status === false) {
        clickDarkMode()
    } else if (status === true) {
        clickLightMode()
    }
})

// 다크/라이트 전환이벤트
function clickDarkMode() {
    localStorage.setItem("theme", "dark")
    button.innerText='Light'
    document.documentElement.setAttribute('data-theme', 'dark')
    status = true
}
function clickLightMode() {
    localStorage.setItem("theme", "light")
    button.innerText='Dark'
    document.documentElement.setAttribute('data-theme', 'light')
    status = false
}

 

 


참조

트위터 JavaScript Dark Mode Toggler

 

 

[자바스크립트] 웹 스토리지 (localStorage, sessionStorage) 사용법

[Javascript] localStorage 사용법 (읽기, 쓰기, 삭제, 키목록 등)

다크모드 토글 기능 구현과 다크모드 토글 디자인 구현

 

Comments