최근 다크모드는 매우 매력적이고 사람들의 소구를 이끌어내는데 효과적입니다.
여러 업체들이 자신의 OS에 다크모드를 적용하고 있습니다.
목차
- 스위치처럼 켜고 끌 수 있는 테마
- OS 레벨의 다크모드
- 유저 선호 성향 저장
- User Agent 스타일 다루기
- 결합 접근
- 디자인 고려
- 여러 환경에서의 다크모드
- 다크모드를 제공하느냐 아니냐
실용적인 코드만 빠르게 확인하고 싶으신 경우에는 5번 결합접근으로 바로 스크롤 해 주시길 바랍니다.
1. 스위치처럼 켜고 끌 수 있는 테마 (1/8)
하나의 테마는 사용자가 처음 방문 할 때 얻는 기본값으로 정의되어야합니다. 대부분의 경우 밝은 테마입니다
다른 테마로 전환하는 방법이 있어야합니다(자동으로 수행 될 수 있음).
사용자가 버튼을 클릭하면 색상 테마가 변경됩니다.
이를 수행하기위한 몇 가지 접근 방식이 있습니다.
body 클래스를 사용하는 방법
<body class="dark-theme || light-theme">
const btn = document.querySelector('.btn-toggle');
btn.addEventListener('click', function() {
document.body.classList.toggle('dark-theme');
})
body {
color: #222;
background: #fff;
}
a {
color: #0033cc;
}
/* Dark Mode styles */
body.dark-theme {
color: #eee;
background: #121212;
}
body.dark-theme a {
color: #809fff;
}
See the Pen Method 1 - Class Swapping by YoungMinKim (@oinochoe) on CodePen.
테마별로 스타일시트를 각각 적용하는 법
<!DOCTYPE html>
<html lang="en">
<head>
<link href="light-theme.css" rel="stylesheet" id="theme-link">
</head>
</html>
const btn = document.querySelector(".btn-toggle");
const theme = document.querySelector("#theme-link");
btn.addEventListener("click", function() {
if (theme.getAttribute("href") == "light-theme.css") {
theme.href = "dark-theme.css";
} else {
theme.href = "light-theme.css";
}
});
커스텀 프로퍼티를 사용하는 것
또한 CSS 맞춤 속성의 강력한 기능을 활용하여 어두운 테마를 만들 수 있습니다.
각 테마에 대해 별도의 스타일 규칙 세트를 작성하지 않아도되므로 스타일 작성이 훨씬 빨라지고 필요한 경우 테마를 훨씬 쉽게 변경할 수 있습니다.
body {
--text-color: #222;
--bkg-color: #fff;
--anchor-color: #0033cc;
}
body.dark-theme {
--text-color: #eee;
--bkg-color: #121212;
--anchor-color: #809fff;
}
body {
color: var(--text-color);
background: var(--bkg-color);
}
a {
color: var(--anchor-color);
}
서버사이드에서 변경하는 것(PHP)
<?php
$themeClass = '';
if (isset($_GET['theme']) && $_GET['theme'] == 'dark') {
$themeClass = 'dark-theme';
}
$themeToggle = ($themeClass == 'dark-theme') ? 'light' : 'dark';
?>
<!DOCTYPE html>
<html lang="en">
<!-- etc. -->
<body class="<?php echo $themeClass; ?>">
<a href="?theme=<?php echo $themeToggle; ?>">Toggle Dark Mode</a>
<!-- etc. -->
</body>
</html>
스타일 시트를 변경할 수도 있습니다.
<?php
$themeStyleSheet = 'light-theme.css';
if (isset($_GET['theme']) && $_GET['theme'] == 'dark') {
$themeStyleSheet = 'dark-theme.css';
}
$themeToggle = ($themeStyleSheet == 'dark-theme.css') ? 'light' : 'dark';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- etc. -->
<link href="<?php echo $themeStyleSheet; ?>" rel="stylesheet">
</head>
<body>
<a href="?theme=<?php echo $themeToggle; ?>">Toggle Dark Mode</a>
<!-- etc. -->
</body>
</html>
서버측 솔루션의 단점은 전환이 발생할 때 새로고침이 발생해야된다는 점이고, 장점은 사용자의 설정된 커스텀화 테마를 유지하는데 유용합니다.
어떤 방법을 사용할 건가요?
가능한 방법을 논의하고 프로젝트의 규모에 따라서 적절히 혼합하거나 선택하여 사용하면 좋을 것 같습니다.
2. OS 레벨의 다크모드(2/8)
많은 운영 체제에서는 사용자가 시스템 설정에서 직접 밝은 테마와 어두운 테마 중에서 선택할 수 있습니다.
그런 상황에서 어떻게 적용시키면 좋을지요? 한번 알아봅시다.
CSS로만 적용하는 방법
다행히 CSS에는 사용자의 시스템 색 구성표 환경 설정을 감지하는 데 사용할 수있는 prefers-color-scheme 미디어 쿼리가 있습니다.
@media (prefers-color-scheme: dark) {
body {
color: #eee;
background: #121212;
}
a {
color: #809fff;
}
}
@media (prefers-color-scheme: light) {
/* Light theme styles go here */
}
Javascript를 이용하는 방법
matchedMedia()를 사용할 수 있습니다.
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
if (prefersDarkScheme.matches) {
document.body.classList.add('dark-theme');
} else {
document.body.classList.remove('dark-theme');
}
자바스크립트 사용에는 단점이 있습니다.
자바스크립트가 CSS 이후에 실행되기 때문에 빠르게 깜박일 수 있습니다.
버그로 잘못 해석 될 수 있습니다.
OS시스템을 오버라이딩
항상 사용자가 테마를 설정했어도 항상 모든 컨텐츠에서 그 테마를 선호하는 것이 아니기 때문에 변경을 해줄 수 있어야 합니다.
/* Default colors */
body {
--text-color: #222;
--bkg-color: #fff;
}
/* Dark theme colors */
body.dark-theme {
--text-color: #eee;
--bkg-color: #121212;
}
/* Styles for users who prefer dark mode at the OS level */
@media (prefers-color-scheme: dark) {
/* defaults to dark theme */
body {
--text-color: #eee;
--bkg-color: #121212;
}
/* Override dark mode with light mode styles if the user decides to swap */
body.light-theme {
--text-color: #222;
--bkg-color: #fff;
}
}
btn.addEventListener("click", function() {
// 만약 OS가 다크모드로 설정되어있다면..
if (prefersDarkScheme.matches) {
// 라이트 테마로 오버라이드 합니다.
document.body.classList.toggle("light-theme");
} else {
document.body.classList.toggle("dark-theme");
}
});
브라우저 지원 범위 (운영체제 설정가능 범위)
prefers-color-scheme 미디어 쿼리의 지원 범위는 Chrome 76+, Firefox 67+, Chrome Android 76+ 및 Safari 12.5+ (iOS의 경우 13+)를 포함한 주요 브라우저에서 지원됩니다.
IE 및 삼성 인터넷 브라우저는 지원하지 않습니다.
80.85%정도이므로 매우 유용한 레벨에 올라왔다고 생각합니다.
현재 다크 모드를 지원하는 운영 체제에는 MacOS (Mojave 이상), iOS (13.0+), Windows (10+) 및 Android (10+)가 있습니다.
3. 유저 선호 성향 저장(3/8)
지금까지 살펴본 내용은 OS 환경 설정 또는 버튼 클릭에 따라 테마를 바꾸는 것입니다.
이는 훌륭하지만 사용자가 사이트의 다른 페이지를 방문하거나 현재 페이지를 새로 고침 할 때 적용되지 않습니다.
사용자의 선택을 저장하여 사이트 전체와 이후 방문시 일관되게 적용되도록 해야합니다.
이를 위해 테마를 전환 할 때 사용자의 선택을 localStorage에 저장할 수 있습니다.
쿠키도 작업에 적합합니다.
localstorage를 사용한 방법
페이지가 다시 로드 될 때 스크립트는 localStorage에서 선택 항목을 가져와 적용합니다.
JavaScript는 종종 CSS 이후에 실행되기 때문에 이 접근 방식은 "Flash Of Incorrect Theme"(FOIT)가 발생하기 쉽습니다.
const btn = document.querySelector(".btn-toggle");
const currentTheme = localStorage.getItem("theme");
// 로컬스토리지에 현재 저장된 색상이 다크이면
if (currentTheme == "dark") {
document.body.classList.add("dark-theme");
}
// 버튼으로 다크모드 및 라이트모드 토글
btn.addEventListener("click", function() {
document.body.classList.toggle("dark-theme");
let theme = "light";
if (document.body.classList.contains("dark-theme")) {
theme = "dark";
}
localStorage.setItem("theme", theme);
});
쿠키를 사용한 방법(PHP)
const btn = document.querySelector(".btn-toggle");
btn.addEventListener("click", function() {
document.body.classList.toggle("dark-theme");
let theme = "light";
if (document.body.classList.contains("dark-theme")) {
theme = "dark";
}
document.cookie = "theme=" + theme;
});
<?php
$themeClass = '';
if (!empty($_COOKIE['theme']) && $_COOKIE['theme'] == 'dark') {
$themeClass = 'dark-theme';
}
?>
<!DOCTYPE html>
<html lang="en">
<body class="<?php echo $themeClass; ?>">
</body>
</html>
별도의 스타일 시트로 나누는 방법도 있습니다.
<?php
$themeStyleSheet = 'light-theme.css';
if (!empty($_COOKIE['theme']) && $_COOKIE['theme'] == 'dark') {
$themeStyleSheet = 'dark-theme.css';
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<link href="<?php echo $themeStyleSheet; ?>" rel="stylesheet" id="theme-link">
</head>
웹 사이트에 로그인하고 프로필 항목을 관리 할 수있는 장소와 같은 사용자 계정이있는 경우 테마 환경 설정을 저장하기에 좋은 장소이기도합니다.
사용자 계정 세부 정보가 저장된 데이터베이스로 보냅니다.
그런 다음 사용자가 로그인하면 데이터베이스에서 테마를 가져 와서 PHP(또는 서버측 스크립트)를 사용하여 페이지에 적용합니다.
이를 수행하는 방법에는 여러 가지가 있습니다.
이 예에서는 데이터베이스에서 사용자의 테마 환경 설정을 가져 와서 로그인 할 때 세션 변수에 저장합니다.
<?php
// 로그인
if (!empty($_POST['login'])) {
...
// 만약 인증에 성공하면
if ($loginSuccess) {
// 유저 테마를 세션에 저장해둡니다.
$_SESSION['user_theme'] = $userData['theme'];
}
}
// 유저 세션 정보가 있으면 세션정보 아니면 쿠키에서 꺼내옵니다.
$themeChoice = $_SESSION['user_theme'] ?? $_COOKIE['theme'] ?? null;
$themeClass = '';
if ($themeChoice == 'dark') {
$themeClass = 'dark-theme';
}
?>
<!DOCTYPE html>
<html lang="en">
<body class="<?php echo $themeClass; ?>">
</body>
</html>
사용자가 로그인하지 않았거나 로그아웃한 경우 쿠키 값이 사용됩니다.
4. User Agent 스타일 다루기(4/8)
예를 들어 페이지가 다크모드와 라이트모드를 둘 다 지원해야 될 때, 둘 다 메타 태그에 공백으로 구분 된 값으로 넣을 수 있습니다. 메일폼 등에서 white로 fix 하고 싶을 때는 <meta name="color-scheme" content="light">로 고정 하시면 됩니다.
<meta name="color-scheme" content="light dark">
<!-- icloud에서는 아래 구문이 없어도 잘 작동했다 -->
<!-- <meta name="supported-color-schemes" content="light dark"> -->
이 메타 태그가 추가되면 브라우저는 페이지의 UA 제어 요소인 사용자의 색 구성표 환경 설정을 고려합니다.
예시 : dark-mode.glitch.me/
테마는 대부분 수동으로 스타일이 지정되지만(UA 스타일보다 우선 적용됨) 지원되는 테마에 대해 브라우저에 알리면 잠재적인 FOIT 상황의 가능성을 최소화하는데 도움이 됩니다. 이는 HTML이 렌더링 되었지만 CSS가 여전히 로드를 기다리고있는 경우에 해당됩니다.
CSS에서도 세팅해줄 수 있습니다.
:root {
color-scheme: light dark;
}
color-scheme은 아직 브라우저 지원이 미흡합니다.
5. 결합 접근(5/8)
위의 방법들을 결합해서 적용해보시죠!
- 시스템 환경 설정에 따라 어둡거나 밝은 테마를 자동으로 로드합니다.
- 사용자가 시스템 기본 설정을 수동으로 재정의 할 수 있습니다.
- 페이지 새로 고침시 사용자가 선호하는 테마 유지
localStorage를 이용한 방법(Javascript)
const btn = document.querySelector(".btn-toggle");
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
// 로컬스토리지
const currentTheme = localStorage.getItem("theme");
// 로컬스토리지 색상 체크
if (currentTheme == "dark") {
document.body.classList.toggle("dark-mode");
} else if (currentTheme == "light") {
document.body.classList.toggle("light-mode");
}
btn.addEventListener("click", function() {
if (prefersDarkScheme.matches) {
document.body.classList.toggle("light-mode");
let theme = document.body.classList.contains("light-mode") ? "light" : "dark";
} else {
document.body.classList.toggle("dark-mode");
let theme = document.body.classList.contains("dark-mode") ? "dark" : "light";
}
localStorage.setItem("theme", theme);
});
쿠키를 사용한 방법(PHP)
<?php
$themeClass = '';
if (!empty($_COOKIE['theme'])) {
if ($_COOKIE['theme'] == 'dark') {
$themeClass = 'dark-theme';
} else if ($_COOKIE['theme'] == 'light') {
$themeClass = 'light-theme';
}
}
?>
<!DOCTYPE html>
<html lang="en">
<body class="<?php echo $themeClass; ?>">
<script>
const btn = document.querySelector(".btn-toggle");
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
btn.addEventListener("click", function() {
if (prefersDarkScheme.matches) {
document.body.classList.toggle("light-mode");
var theme = document.body.classList.contains("light-mode") ? "light" : "dark";
} else {
document.body.classList.toggle("dark-mode");
var theme = document.body.classList.contains("dark-mode") ? "dark" : "light";
}
document.cookie = "theme=" + theme;
});
</script>
</body>
</html>
6. 디자인 고려(6/8)
좋은 규칙은 이미지가 어두운 배경에있을 때 눈에 편안하게 보이도록 이미지의 밝기와 대비를 약간 낮추는 것입니다.
매우 어두운 배경의 매우 밝은 이미지는 혼란스러울 수 있으며 이미지를 어둡게하면 그 무거운 대비를 줄일 수 있습니다.
CSS filter() 함수는 이것을 처리 할 수 있는 이상적인 방법입니다.
다크모드에서 색상 대비
// 클래스 방법
body.dark-theme img {
filter: brightness(.8) contrast(1.2);
}
// 미디어쿼리 방법
@media (prefers-color-scheme: dark) {
img {
filter: brightness(.8) contrast(1.2);
}
}
<picture>
<!-- 라이트모드 / 지정하지 않았을 때 해당 이미지 사용 -->
<source srcset="photo-light.png" media="(prefers-color-scheme: light) or (prefers-color-scheme: no-preference)">
<!-- 다크모드일 때 해당 이미지 사용 -->
<source srcset="photo-dark.png" media="(prefers-color-scheme: dark)">
</picture>
여기서 단점은 CSS를 사용할 때 하나만 처리하면 되는 두 개의 파일을 제공해야한다는 것입니다.
다크모드 그림자
다크모드에서 그림자는 매우 까다롭습니다.
밝은 색상을 사용하여 어두운 그림자를 단순히 반전시키면 어두운 배경에 밝은 그림자가있는 보기에 좋지 않은 화면이 나타납니다.
다크모드 투명도
불투명도를 사용하여 깊이를 전달하고 불투명도가 높은 영역은 깊이가 더 낮습니다.
즉, 고도가 더 높은 요소는 배경에 깊이가 가까운 요소보다 불투명도가 낮아야합니다.
다크모드 타이포
다크모드에서 타이포도 마찬가집니다.
여기서 비결은 이미지와 비슷합니다.
대비의 균형을 맞춰야 합니다.
너무 무거운 글꼴을 사용하면 화면에서 울퉁불퉁한 텍스트가 표시됩니다.
너무 밝은 글꼴을 사용하면 더 자세히보기 위해 화면을 보는동안 눈이 피로 해 집니다.
다크모드 아이콘
아이콘은 텍스트와 이미지 사이의 일종의 교차이기 때문에 까다롭습니다.
하지만 SVG 아이콘으로 작업하는 경우 CSS로 fill을 변경할 수 있습니다.
반면에 글꼴 아이콘을 사용하는 경우 색상 속성을 변경하면됩니다.
/* SVG icon */
body.dark-theme svg.icon path {
fill: #efefef;
}
/* Font icon (예시 : Font Awesome) */
body.dark-theme .fa {
color: #efefef;
}
텍스트에 적용되는 많은 동일한 디자인 고려사항이 일반적으로 아이콘에도 적용됩니다.
예를 들어, 전체 흰색과 두꺼운 윤곽선을 사용하지 않아야합니다.
다크모드 색상
순수한 검정색 배경에 새하얀 텍스트가 표시됩니다.
여기서 트릭은 텍스트에 미색을 사용하고 배경에 미색을 사용하는 것입니다.
예를 들어 머티리얼 디자인 가이드 라인은 배경으로 #121212를 권장합니다.
("미색(米色)"이라는 색상은 쉽게 말해서 "쌀색"입니다. 쌀알의 색깔입니다. 백미는 아니고 현미의 색입니다. 한자로 米(쌀 미)자를 씁니다. 미색은 공식적인 컬러명은 아니고 의류계 등에서 관용적으로 부르는 색깔 이름 같더군요.)
첫 번째 팁은 고대비 검사기를 통해 색상 비율이 4.5 : 1의 대비 비율인 AA 등급에 대한 WCAG의 지침을 준수하는지 확인하는 것입니다.
어두운 모드 디자인으로 작업 할 때 저채도가 색상이 좋습니다.
지나치게 밝은 이미지를 방지하고 효과적인 명암비를 생성 할 수있는 충분한 공간을 제공합니다.
다음으로, 강조 색상은 향상을위한 것임을 기억하세요.
무조건 어두운 테마 배경색보다 밝을 가능성이 높기 때문에 원색을 사용하는 것은 밝은 이미지나 무거운 흰색 텍스트처럼 눈에 거슬리고 딱딱합니다.
다크 모드에 대한 머티리얼 디자인 가이드 라인은 다크 모드 디자인 모범 사례에 대한 유용한 리소스입니다.
명심해야 할 더 많은 팁을 읽어 볼 가치가 있습니다.
material.io/design/color/dark-theme.html
7. 여러 환경에서의 다크모드(7/8)
Youtube의 경우 다크모드를 html 선택자 아래의 변수에 모든 색상을 정의하고 다크모드의 경우 html:not(.style-scope)[dark] 아래에 정의되어 있습니다.
실제로 CSS 사용자 정의 속성 접근 방식이 가장 인기있는 것 같습니다.
Dropbox Paper, Slack, Facebook에서 사용되고 있습니다.
Simplenote는 모든 밝은 스타일 규칙이 .theme-light 부모 클래스의 자손이고 모든 어두운 스타일이 .theme-dark 클래스에 속하는 클래스 교체 방법을 사용합니다.
테마가 전환되면 적절한 클래스가 태그에 적용됩니다.
Twitter는 "Default", "Dim" 및 "Lights out"과 같은 몇 가지 테마를 선택할 수 있습니다.
8. 다크모드를 제공하느냐 아니냐(8/8)
이제 다크모드에 대해서 방법들 디자인들 여러 사례들까지 알아보았습니다.
원론적으로 돌아와서 다크모드를 제공할 것인지 아닌지에 대해서 고민해봅니다.
양쪽 모두에 완벽하게 타당한 이유가 있습니다.
이러한 이유 중 일부는 사용자 경험의 범위를 벗어나 타이밍, 예산 및 리소스와 같은 것을 포함합니다.
다음은 다크 모드를 원하는 이유입니다.
- 멋지고 트렌디합니다.
- 눈부시게 밝은 테마로 눈에 피로감을 느끼는 사람들에게 지원하여 접근성을 높입니다.
- 이를 통해 사용자는 콘텐츠를 사용하는 가장 편안한 방법을 결정하는 동시에 사물의 모양과 느낌을 제어 할 수있는 방법을 제공합니다.
- 밝은 색상이 더 많은 에너지를 소비하는 OLED 화면이 있는 장치의 배터리 수명을 보존하는 데 다크모드가 도움이됩니다.
그 외에도 여러가지 이유들이 있습니다.
여러분의 생각은 어떤가요?
이상입니다.
'CSS' 카테고리의 다른 글
Grid로 가장자리 색상바를 만드는 방법 (0) | 2021.02.21 |
---|---|
Repaint만 일어나는 속성, 아예 Repaint도 일어나지 않는 속성 (0) | 2021.02.21 |
CSSOM이란? (브라우저 렌더링 과정에 대하여) (0) | 2021.02.14 |
Sass 와 새로운 CSS 기능의 충돌! (0) | 2021.02.12 |
CSS Contain 속성에 대하여.. (0) | 2021.02.12 |
댓글