다크 모드의 여섯 단계 (2024)
(cssence.com)- 브라우저 기본 기능부터 JavaScript 미디어 쿼리까지, 다크 모드 구현 범위를 점진적으로 넓혀 가는 8단계 구분 정리
- 가장 단순한 방식은
<meta name="color-scheme" content="light dark">또는color-scheme: light dark선언만으로 사용자 색상 스킴 선호를 따르게 하는 구성 - 더 높은 단계에서는
light-dark()함수,@media (prefers-color-scheme: dark), 스킴별 분리 스타일시트로 색상뿐 아니라 이미지와 그림자까지 폭넓은 조정 가능 - 사용자 시스템 설정만 따르지 않고 Automatic·light·dark 3가지 선택지를 제공하는 전환기 구성 가능하며,
:has()와 실제 meta 요소를 기준으로 테마 판별 가능 - Safari의 접근성 한계와 인쇄 시
prefers-color-scheme동작 관찰까지 포함되며, 최근 CSS 기능만으로도 라이트·다크 모드 내장이 쉬워졌음이 드러남
다크 모드 단계별 구현
-
Level 1: Barebone
- CSS 한 줄 없이도 light/dark 구분 활성화 가능하며, 문서 head에
<meta name="color-scheme" content="light dark">추가만으로 브라우저가 사용자 색상 스킴 선호를 따르기 시작함 content속성의 항목 순서는 이론상 의미가 있으며, 색상 스킴 선호를 지정하지 않은 사용자는 공백으로 구분된 목록의 첫 번째 값을 받음- 현재 운영체제 설정에는 색상 스킴을 선택하지 않는 옵션이 없어, 실제로는 운영체제 설정과 일치하는 스킴으로 귀결됨
content에 단일 값만 지정할 수도 있으며, 이 경우 사용자 선호를 고려하지 않고 해당 스킴을 강제 적용함- 이 메타 태그는 어느 정도 다음 단계의 CSS 방식과 대응하는 HTML 측 방식 역할 수행
- CSS 한 줄 없이도 light/dark 구분 활성화 가능하며, 문서 head에
-
Level 2: Basic
- CSS에서는
html { color-scheme: light dark; }선언으로 라이트/다크 모드 구분 적용 가능 - 이미 DOM에 메타 태그가 있다면 이 선언은 필요하지 않으며, HTML을 제어할 수 있다면 브라우저가 CSS 파싱 전부터 지시를 알 수 있는 메타 태그 사용 권장
- 두 방식 모두 사용자 에이전트 기본 스타일과 그에 포함된 라이트/다크 모드를 활용할 수 있게 해줌
- 여기에 CSS를 추가하되 CSS system colors 사용 위주로 제한하면 꽤 정돈된 디자인 구현 가능
- 메타 태그가 항상 문서 전체에 적용되는 것과 달리, CSS
color-scheme선언은 루트 요소 외 다른 위치에도 설정 가능하며, 이 차이로 추가 활용 여지 존재
- CSS에서는
-
Level 3: Benign
- 비교적 최근 추가된 CSS의
light-dark()색상 함수로 단순한 라이트/다크 모드 조정 가능 - 예시에서는
background-color: light-dark(black, white);와color: light-dark(white, black);처럼 사용하며, 첫 번째 인수는 라이트 모드에 적용되고 두 번째 인수는 다크 모드에 적용됨 - 인수에는 실제 색상을 직접 넣을 수도 있고, 색상으로 해석되는 custom properties를 넣을 수도 있음
- 이 글 전체에서 이 단계만 작성 시점 기준 브라우저 지원이 충분하지 않음
- 비교적 최근 추가된 CSS의
-
Level 4: Bold
- 전통적인
@media (prefers-color-scheme: dark)미디어 쿼리로 다크 모드 전환 구현 가능 light또는dark어느 쪽을 질의하든, 단순 색상 변경에 한정되지 않는 최대 수준의 커스터마이징 가능- 다크 모드에서 이미지를 필터로 저채도 처리하거나, 박스 그림자를 외곽선으로 대체하는 식의 조정도 모두 가능
- 전통적인
-
Level 5: Bisectional
- 미디어 쿼리는 HTML에서도 사용할 수 있으며,
link요소의media속성에 넣어 스킴별 스타일시트 분리 가능 - 예시로
light.css와dark.css를 각각prefers-color-scheme: light와prefers-color-scheme: dark에 연결하는 방식 제시 - 커스터마이징 범위가 큰 경우 전용 파일 구성이 적합하며, 브라우저는 질의와 맞지 않는 CSS 파일을 무시할 수 있어 다운로드 대상이 하나 줄어들 수 있음
- 미디어 쿼리는 HTML에서도 사용할 수 있으며,
-
Level 6: Ballistic
- JavaScript에서는
window.matchMedia('(prefers-color-scheme:dark)')로 색상 스킴 미디어 쿼리 사용 가능 - 다른 미디어 쿼리와 같은 방식으로 라이트 또는 다크 스킴 여부를 질의한 뒤, 그 결과를 바탕으로 원하는 처리 수행 가능
- 실제 구현에서는 앞선 단계들의 기법을 한 가지만 고수하지 않고 혼합 적용 가능
- JavaScript에서는
사용자 전환기와 고급 패턴
-
Level 7: Beyond
- 사용자 시스템 선호에만 의존할 필요 없이 color scheme switcher 구축 가능
- 이 전환기는 단순 불리언이 아니며, 초기 기본값으로
prefers-color-scheme를 따르는 Automatic 모드 필요 - 그 위에 전환기를 얹으면 사용자는 Automatic, light, dark의 세 가지 모드 중 하나 선택 가능
-
Level 8: Beguiling
- Level 7 전환기 구현 시 일반적으로 HTML 요소에
.dark클래스나data-theme="dark"같은 속성을 추가하는 방식이 흔함 - 대신
:has()를 사용해 실제<meta name="color-scheme" content="dark">존재 여부를 직접 질의 가능 - 예시에서는
html:has(meta[name="color-scheme"][content="dark"])선택자 아래에서--color-bg,--color-text같은 CSS 변수를 다크 모드 값으로 설정 - 별도 클래스나 데이터 속성 없이도 실제 meta 요소를 기준으로 테마 판별 가능
- Level 7 전환기 구현 시 일반적으로 HTML 요소에
추가 논의와 관찰
-
CSS Naked Day 관찰
- 스타일 제거 후 방문한 거의 모든 사이트에서 다크 모드 부재가 눈에 띄었고, 이것이 다크 모드 단계 구분으로 이어짐
- 새 사이트를 처음부터 구축하면서 새 스타일을 작성할 경우, 최근의 CSS 기능으로 라이트/다크 모드 내장이 매우 쉬워졌다는 언급 포함
-
Safari 접근성 이슈
- 비교적 최근까지 Safari는 다크 모드에서 접근 가능한 링크 색상을 제공하지 않았다는 지적 포함
- 이전 CSS Naked Day에는 이 문제를 발견하고 메타 태그를 제거한 뒤 라이트 색상 스킴만 사용한 경험 언급
- 이후 다시 메타 태그를 추가했지만, 구버전 Safari 사용자에게는 접근성 저하가 생길 수 있음을 인지
- Safari의 다크 모드에서 텍스트 상자에 보이는 테두리 부재도 확인됨
- 사용자 에이전트 스타일만으로는 올바른 시맨틱 HTML을 사용해도 완전한 접근성을 보장하지 못해, 향후 CSS Naked Day에도 충분한 스타일을 유지하는 방안 고민
-
인쇄와
screen and조건- Bisectional 예시에서
screen and ...를 사용한 이유로 프린터 대상 제외 의도 언급 - 테마 비의존 코어 스타일시트나 전용 인쇄 스타일시트가 따로 있다고 가정하고, 프린터에서 다크 모드가 잉크를 많이 쓸 수 있어 안전하게 분리하려는 판단 제시
- 실제 테스트에서는 시스템 다크 모드를 켠 상태로 인쇄해도 검은 텍스트와 흰 종이만 출력되었고, 브라우저들이 인쇄에 해당 다크 모드 스타일을 적용하지 않는 것으로 관찰됨
- 추가 테스트에서 인쇄 미리보기에서는
prefers-color-scheme가 항상 light로 보고되었으며, Firefox와 Chromium에서 확인됨 - 검은 종이와 흰 잉크를 쓰는 프린터가 있다면 아쉽겠다는 농담성 언급 포함
- Bisectional 예시에서
GeekNews Weekly에 포함된 글입니다.
에디터 코멘트 보기
댓글과 토론
Hacker News 의견들
- 커스텀을 많이 한다면 전용 파일이 말은 되지만, 미디어 쿼리에 안 맞는 CSS가 다운로드조차 안 된다는 설명은 실제 브라우저 동작과 다르다고 봄. 내 경험상 브라우저는 결국 전부 다운로드하고, 우선순위만 다르게 줄 뿐임
- 서버에서 초기 콘텐츠를 기다리는 동안 생기는 플래시뱅 같은 번쩍임을 막을 방법이 아직 없는지 궁금했음
- 나는 Firefox의
userContent.css에서 background-color를 지정하는 방식이 괜찮다고 봄 - 나는 그냥 화면 밝기를 낮추고 다크 모드를 끄면 플래시뱅이 없어졌음. 덤으로 배터리도 더 오래감
- 나는 Firefox의
- 나는 이 글이 다크 모드 배경의 검정 농도 취향 얘기일 줄 알았음. 순수한 검정이 OLED에서 배터리 효율이 더 좋다는 말도 들었고, 완전한 검정보다 잉크 덜한 회색을 더 좋아하는 사람도 알고 있음. 다만 굳이 여섯 단계까지 필요한지는 잘 모르겠고, 체감 가능한 건 많아야 3~4단계쯤이라고 느꼈음
- 나는 더 보편적인 해법이 Reader Mode 호환성 표준화라고 생각했음. 각 사이트가 모든 사용자 취향을 일일이 맞추는 n x m 문제 대신, 사이트는 하나의 단순한 콘텐츠 뷰만 지원하고 브라우저가 그 위에서 사용자별 설정을 맡는 구조가 더 낫다고 봄
- 나는 OLED에서는 순수한 검정을 선호하는 편임. 픽셀이 덜 켜질수록 번인 부담이 줄어든다고 느끼고, 어차피 수명이 한정돼 있으니 장기적으로는 모니터를 2~3년보다 5년 이상 쓰고 싶다는 쪽임
- 내 기준 최고 레벨은 9, 아니면 0인데, 그냥 컴퓨터를 끄고 가서 잠을 자는 것임
- 나는 OP가 3상태 토글을 제대로 구현한 점이 반가웠음
- 나는 스크롤을 내려가면서 단계가 동적으로 적용됐으면 더 재밌었겠다고 생각했음
- 아니면 페이지의 적절한 위치마다 독자가 직접 단계 선택을 할 수 있어도 괜찮겠다고 봤음
- 내가 보기엔 8단계 아닌가 싶었음
- 지금이 2024년이라는 느낌이었음
- 이 상황에서 떠오르는 건 역시 xkcd 3227였음