TL;DR

  • light-dark()는 미디어 쿼리 없이 라이트 모드와 다크 모드의 색상을 지정하는 간결한 방법이지만, 지원율이 약 90%여서 대체 색상 설정이 중요함.
  • 브라우저에 지원 색상 체계를 알리는 방법은 HTML의 color-scheme 메타 태그와 CSS :root 선언 두 가지임.
  • 각 light-dark() 선언 앞에 대체 색상을 지정하면 해당 함수를 지원하지 않는 브라우저에서도 라이트 모드 색상을 유지할 수 있음.
  • color-scheme은 지원하지만 light-dark()는 지원하지 않는 브라우저에서 다크 배경과 회색 글자가 겹치는 문제는 @supports 조건부 선언으로 방지할 수 있음.
  • light-dark()는 성능을 유의미하게 개선하지는 않지만 색상 코드의 길이와 이해하기 쉬운 정도를 개선해 유지보수에 도움이 됨.

라이트 모드와 다크 모드의 색상 지정

  • 사용자의 라이트 모드 또는 다크 모드 선호를 존중하는 방법으로 CSS의 light-dark() 함수를 검토함. 이 함수는 2024년 무렵 대부분의 최신 브라우저에서 사용할 수 있게 됨.
  • 기존에는 기본 색상을 지정한 뒤 prefers-color-scheme: dark 미디어 쿼리에서 다크 모드 색상을 덮어쓰는 방식을 사용함.
  • light-dark()를 쓰면 텍스트 색상과 배경색을 각각 한 줄로 지정할 수 있음. 브라우저는 라이트 모드에서 첫 번째 값을, 다크 모드에서 두 번째 값을 선택함.
  • 예시에서는 라이트 모드가 검은색 텍스트와 흰색 배경을, 다크 모드가 흰색 텍스트와 검은색 배경을 사용함.

먼저 할 일

  • light-dark()가 동작하려면 웹사이트가 지원하는 색상 체계를 브라우저에 알려야 함.
  • HTML의 <head>에 <meta name="color-scheme" content="light dark">를 넣으면 사용자가 다크 모드를 켰을 때 브라우저가 제어하는 기본 색상과 인터페이스 요소에도 어두운 색상을 적용할 수 있음. CSS 의존도가 낮은 데모 사이트인 HTML Playground에서 이 방식을 사용함.
  • 또는 CSS의 :root 의사 클래스를 통해 color-scheme: light dark를 지정할 수 있음. 대부분의 경우 CSS 방식이 적합함.

안전한 사용

  • prefers-color-scheme을 지원하지 않는 브라우저는 미디어 쿼리 방식에서 라이트 모드 색상을 사용함. 반면 light-dark()를 지원하지 않는 브라우저는 해당 함수가 포함된 선언 전체를 무시함.
  • 작성 시점의 light-dark() 브라우저 지원율은 거의 90%로 양호하지만, 대체 색상 없이 사용하기에는 충분히 높지 않음.

대체 색상 지정

  • 위험을 줄이는 방법은 각 함수 선언 앞에 대체 색상을 지정하는 것임.
  • light-dark()를 지원하지 않는 브라우저는 첫 번째 색상 선언을 적용하고, 함수가 포함된 두 번째 선언은 무시하므로 라이트 모드에서 검은색 텍스트와 흰색 배경을 표시함.

대체 색상을 지정하지 않는 경우

  • 색상 선언의 반복을 줄이고 싶거나 light-dark() 미지원 브라우저의 기본 색상이 어떻게 표시되는지 크게 상관하지 않는 경우에는 대체 색상을 생략할 수도 있음. 다만 위험이 다소 커짐.
  • 웹사이트에서 사용하는 색상 예시는 라이트 모드의 어두운 회색 텍스트(#0b0c0c)와 흰색 배경(#fff), 다크 모드의 매우 밝은 회색 텍스트(#f2f2f2)와 어두운 회색 배경(#262626)임.
  • 대체 색상을 생략하면 light-dark() 미지원 브라우저는 일반적으로 라이트 모드에서 검은색 텍스트와 흰색 배경을, 다크 모드에서 흰색 텍스트와 어두운 회색 배경을 사용함. 원하는 색상과 정확히 같지는 않지만 웹사이트가 괜찮게 보일 수 있음.
  • 이 방식은 위험이 있으므로 충분한 테스트가 필요함.

구현 시점에 따른 문제

  • 실제 사이트 구현에서는 브라우저 기본값을 활용할 수 있는 부분과 이중 색상 선언이 필요한 부분을 결합함.
  • 텍스트 색상에는 먼저 약간 검은색에 가까운 색(#0b0c0c)을 대체 색상으로 선언한 다음 light-dark()를 지정하고, 배경색에는 light-dark()를 사용함. 라이트 모드는 흰색 배경, 다크 모드는 어두운 회색 배경을 사용하며, 함수 미지원 시에는 어두운 텍스트 색상이 대체값으로 남음.
  • 검은색 텍스트와 흰색 배경의 높은 대비는 난독증이 있는 일부 독자에게 시각적 부담을 줄 수 있으므로, light-dark() 미지원 환경에서도 선택한 매우 어두운 회색 텍스트를 유지하는 편을 선호함.
  • 그러나 color-scheme이 안정적으로 지원되기 시작한 2022년 초와 light-dark()가 지원되기 시작한 2024년 중반 사이에는 약 2년 반의 간격이 있음. 지금도 Opera Mini 등 일부 브라우저는 color-scheme은 지원하지만 light-dark()는 지원하지 않음.
  • 이런 지원 불일치가 있는 브라우저에서 다크 모드를 선호하는 방문자는 어두운 회색 대체 텍스트와 브라우저 기본 다크 배경을 함께 보게 됨.
  • 회색 글자와 회색 배경이 겹치는 문제를 피하려면 color-scheme 선언을 @supports (color: light-dark(black, white)) 조건 안에 넣을 수 있음. 브라우저가 light-dark()도 지원할 때만 두 색상 체계를 활성화하며, 지원 불일치가 있는 브라우저는 선언을 건너뛰어 대체 텍스트 색상과 브라우저 기본 라이트 배경을 사용함.

사용할 가치가 있는가?

  • light-dark()는 색상 선언을 간결하게 만들며, 작성자의 관점에서는 미디어 쿼리보다 읽기 쉬움. 다만 개발자가 아니라 사용자를 위한 이점이 있는지도 고려할 필요가 있음.
  • 코드베이스를 light-dark() 방식으로 바꿨을 때 생성된 CSS는 0.923kB 감소했지만 압축 파일 크기는 소폭 증가함. 텍스트 줄 수가 줄어도 압축 효율이 반드시 좋아지는 것은 아니며, 기존의 미디어 쿼리 중심 CSS가 더 잘 압축됨.
  • 압축 전송 크기 변화는 Gzip에서 149바이트 증가, Brotli에서 132바이트 증가로, 실제 우려를 낳을 정도는 아님. 파싱 시간은 0.156ms 감소함.
  • 종합하면 light-dark()는 성능에 유의미한 차이를 만들지는 않지만 색상 체계 코드를 짧고 이해하기 쉽게 만듦. 적절한 대체 색상을 필요한 곳에 두면 유지보수성 개선만으로도 사용할 가치가 있음.