사라져가는 다크모드를 위하여: 테마를 위한 지속 쿠키 도입기
2025년 4월 1일
목차
들어가면서
최근 블로그에 관한 피드백을 한 지인으로부터 받게 되었습니다. 다음과 같은 질문이었습니다.
“블로그의 테마 쿠키를 보니 세션 쿠키로 설정되어 있던데, 혹시 지속 쿠키를 사용하지 않으신 특별한 이유가 있으신가요? 세션 쿠키는 브라우저를 종료하면 삭제되어서 여쭤봅니다.”
이 질문을 받고, 무심코 넘겼던 테마 설정 방식에 대해 다시 생각해보게 되었습니다. 브라우저를 닫았다가 다시 열면 테마가 초기화되는 현상은 분명 사용자 입장에서 불편하게 느껴질 수 있는 부분입니다. 실제로 지금까지는 세션 쿠키로도 충분하다고 판단했기에 별다른 의문 없이 사용해왔지만, 이 피드백을 계기로 테마 상태를 어떤 방식으로 저장하고 유지하는 것이 적절할지 고민하게 되었습니다.
쿠키, 다시 보기
회고를 진행하기에 앞서, 먼저 질문을 하나 던져 봅시다.
"쿠키란 무엇인가요?"
쿠키(cookie)는 사용자의 웹 브라우저에 저장되는 작은 데이터 조각으로, 웹사이트가 사용자의 상태나 정보를 기억할 수 있도록 도와주는 수단입니다. 서버 또는 클라이언트에서 설정할 수 있으며, 이후 사용자가 해당 사이트를 다시 방문할 때 요청과 함께 자동으로 전송됩니다.
이렇게 전송된 쿠키는 로그인 상태 유지, 테마와 같은 사용자 선호 설정 저장, 방문 이력 기록 등에 사용될 수 있습니다.
세션 쿠키 vs 지속 쿠키
쿠키는 유효 기간이 명시되었는지에 따라 두 가지로 나뉩니다:
-
세션 쿠키(Session Cookie)
만료 시간이 명시되지 않은 쿠키입니다. 브라우저를 종료하면 자동으로 삭제됩니다.
예: 로그인한 상태를 유지하되, 브라우저를 닫으면 로그아웃되도록 처리하는 경우 -
지속 쿠키(Persistent Cookie)
명시적인Expires
또는Max-Age
속성이 설정된 쿠키로, 브라우저를 닫더라도 일정 기간 동안 유지됩니다.
예: 다크모드 설정처럼 사용자의 선호를 장기간 기억할 필요가 있는 경우
클라이언트 측에서의 설정
JavaScript에서 쿠키를 설정할 때는 document.cookie
를 사용합니다.
document.cookie = 'theme=dark; max-age=604800; path=/; SameSite=Lax';
각 속성은 다음과 같은 의미를 가집니다:
theme=dark
: 저장할 쿠키 값max-age=604800
: 7일 동안 유지path=/
: 사이트 전체에서 유효SameSite=Lax
: 보안 속성
이처럼 쿠키는 짧고 간단한 문자열 조각이지만, 사용자 경험의 연속성과 품질을 좌우할 수 있는 중요한 요소입니다. 특히 테마 설정처럼 사용자의 '선호'가 반영된 값은 가능한 한 지속적으로 유지되어야 하며, 이를 위해서는 세션 쿠키보다는 지속 쿠키가 더 적합한 선택일 수 있습니다.
세션에서 지속 쿠키로 전환하기
쿠키의 개념과 세션, 지속 쿠키의 차이점에 대한 이해를 바탕으로 기존의 ThemeProvider
를 다음과 같이 개선하게 되었습니다.
변경 전: 세션 쿠키
기존에는 toggleTheme
함수 안에서 document.cookie
를 통해 쿠키를 설정하되, max-age
나 expires
값을 지정하지 않았습니다. 따라서 기본적으로 브라우저 세션이 끝나면 해당 쿠키는 삭제되었습니다.
document.cookie = `theme=${newTheme}; path=/`;
변경 후: 지속 쿠키
쿠키가 브라우저 종료 후에도 유지되도록 하기 위해, max-age
값을 명시한 형태로 변경하였습니다. 또한 쿠키 옵션을 상수화하여 재사용성과 가독성을 높였습니다.
document.cookie = `${THEME.COOKIE.NAME}=${newTheme}; max-age=${THEME.COOKIE.MAX_AGE}; ${THEME.COOKIE.OPTIONS}`;
또한 테마 초기화 시점에서도 동일한 방식으로 쿠키를 설정하여, 테마 설정이 브라우저 재접속 이후에도 유지되도록 하였습니다.
useEffect(() => {
document.cookie = `${THEME.COOKIE.NAME}=${initialTheme}; max-age=${THEME.COOKIE.MAX_AGE}; ${THEME.COOKIE.OPTIONS}`;
}, [initialTheme]);
이러한 수정은 사용자가 다크모드 혹은 라이트모드로 설정한 테마가 브라우저를 닫았다 다시 열어도 유지되는 효과를 가져오며, 결과적으로 더 일관된 사용자 경험을 제공할 수 있게 되었습니다.
쿠키를 어떻게 갱신할 것인가
지속 쿠키를 도입하면서 가장 고민했던 부분은 언제 어떤 방식으로 쿠키를 갱신할 것인가였습니다. 사용자가 테마를 설정하고 나서 일정 기간 동안 그 상태를 유지하도록 하는 것이 목표였기 때문에, 쿠키를 무조건 매번 설정하는 방식과 조건부로 설정하는 방식 사이에서 선택이 필요했습니다.
7일의 기적
지속 쿠키를 사용할 때 중요한 요소 중 하나는 쿠키의 유효 기간 설정입니다. 쿠키의 수명은 max-age
혹은 expires
속성으로 설정되며, 너무 짧으면 사용자 경험이 단절되고, 너무 길면 보안상 문제가 될 수 있습니다.
이를 설정함에 있어, 저는 cookiestatus.com에서 정리한 주요 브라우저의 퍼스트 파티 쿠키 수명 정책을 참고했습니다:
브라우저 | 수명 제한 | 비고 |
---|---|---|
Chrome | 400일 | — |
Safari | 7일 | Intelligent Tracking Prevention (ITP) 적용 |
Firefox | 기본적으로 없음, 단 조건부 삭제 가능 | 45일간 사용자 상호작용 없는 추적 도메인은 삭제 대상 |
Edge | Chrome 기반과 동일 | — |
Brave | 기본적으로 추적 차단, 7일 제한 가능성 있음 | 상황에 따라 달라짐 |
이 중 Safari는 ITP(Intelligent Tracking Prevention) 정책에 따라 퍼스트 파티 쿠키라도 7일 후 만료되는 제약이 있으며, Firefox 역시 특정 조건 하에서 쿠키를 자동으로 삭제합니다. 예를 들어, 추적자로 간주되는 도메인 중 45일 이내 사용자 상호작용이 없는 경우, 저장소가 주기적으로 초기화됩니다.
따라서 모든 브라우저 환경에서 테마 상태가 예상대로 유지되도록 하기 위해, 저는 max-age
값을 7일로 설정하였습니다. 이는 Safari의 제한에 대응하면서, Firefox의 조건부 정책에도 어느 정도 대비할 수 있는 실용적인 기준이라고 판단했습니다.
매번 설정하는 현재 방식
현재 블로그에서는 페이지가 로드될 때마다 document.cookie
를 통해 쿠키를 설정하는 방식을 사용하고 있습니다. 코드가 단순하고 직관적이며, 클라이언트 환경에서 빠르게 구현할 수 있다는 장점이 있습니다.
useEffect(() => {
document.cookie = `${THEME.COOKIE.NAME}=${initialTheme}; max-age=${THEME.COOKIE.MAX_AGE}; ${THEME.COOKIE.OPTIONS}`;
}, [initialTheme]);
또한 테마를 전환할 때도 동일한 방식으로 쿠키를 재설정합니다.
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
document.cookie = `${THEME.COOKIE.NAME}=${newTheme}; max-age=${THEME.COOKIE.MAX_AGE}; ${THEME.COOKIE.OPTIONS}`;
document.documentElement.classList.toggle('dark');
};
조건부 갱신 방식과의 비교
한편으로는, 쿠키에 생성 시각을 저장하고 일정 시간이 지났을 때만 쿠키를 갱신하는 방식도 고려해보았습니다. 예를 들어, 쿠키에 타임스탬프를 포함하여 6일 이상이 경과했을 때만 새로운 쿠키를 설정하는 방식입니다. 이 방법은 불필요한 쿠키 갱신을 줄일 수 있고, 구조적인 확장에도 유리합니다.
항목 | 매번 설정 (현재 방식) | 조건부 갱신 (타임스탬프) |
---|---|---|
쿠키 갱신 빈도 | 페이지 로드 시마다 항상 갱신 | 일정 시간 경과 시에만 갱신 |
성능 부하 | 쓰기 연산이 매번 발생 | 쓰기 연산이 줄어듦 |
코드 복잡도 | 단순하고 직관적 | 유틸리티 함수 및 시간 계산 로직 필요 |
구현 난이도 | 쉽고 빠르게 적용 가능 | 상대적으로 구현 복잡 |
유지보수성 | 구조화는 어려우나 간단한 유지보수 가능 | 구조화되어 유지보수와 확장에 유리 |
사용자 경험 차이 | 없음 | 없음 |
나오면서
블로그의 규모나 페이지 사용 패턴을 고려했을 때, 현재 방식은 성능에 거의 영향을 주지 않으며 구현과 유지보수가 용이하다는 장점이 있습니다. 더 구조적인 조건부 갱신 방식도 고려해보았지만, 현재로서는 매번 쿠키를 설정하는 방식이 개인 블로그 수준에서는 충분히 합리적인 선택이라고 판단했습니다. 추후 필요에 따라 개선할 수 있도록 가능성은 열어두되, 지금의 단순한 구조가 오히려 유지보수 측면에서는 유리하다고 생각합니다.
이번 작업을 통해 기술을 올바르게 이해하고 사용하는 방법에 대해 다시 한번 생각해보게 되었습니다. 처음에는 단순히 쿠키의 수명만 연장하면 된다고 생각했지만, 실제로는 각 브라우저의 정책, 사용자의 경험, 코드의 구조 등 다양한 요소들이 얽혀 있다는 사실을 알게 되었습니다. 앞으로도 기술을 사용할 때는 기능만이 아니라 맥락과 목적에 맞게 적용하는 태도가 중요하다는 점을 잊지 않으려 합니다.