이번 포스팅에서는 블로그에 다크 모드를 적용하고, 다크/라이트 모드를 전환할 수 있는 토글 스위치를 만드는 방법을 알아보자.
특히, 사용자 기기의 기본 모드 설정을 우선으로 하고, 이후 사용자가 설정한 다크 모드 선택을 저장하여 브라우저에 기록하는 기능도 포함시킨다.
다크 모드 기본 설정 및 Font Awesome 아이콘 불러오기
먼저 다크 모드 구현을 위해 필요한 설정을 적용하고, 토글 스위치 아이콘에 사용할 Font Awesome 아이콘을 불러오자. 아이콘을 추가하기 위해서는 Font Awesome의 CDN 링크를 추가해야 한다. 이번에는 `fa-sun`과 `fa-moon` 아이콘을 사용할 것이다.
Font Awesome CDN 추가
<head>
<!-- Font Awesome 아이콘 불러오기 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
Font Awesome을 통해 태양과 달 모양의 아이콘을 사용하면 사용자가 선택한 테마에 따라 손쉽게 아이콘을 교체할 수 있다.
기본 다크 모드 설정
다크 모드의 스타일은 기본적으로 사용자의 시스템 설정을 우선으로 하며, 이후 사용자가 스위치로 선택한 모드가 있다면 해당 모드를 우선적으로 적용하게 된다. 다음과 같은 CSS에서 data-theme="dark"
속성을 기준으로 다크 모드를 정의한다. 이 속성을 이용해 다크 모드가 적용될 때 색상과 배경이 자동으로 변경될 수 있도록 한다.
다크 모드 스타일
/* 다크 모드 지원을 위한 추가 스타일 */
[data-theme="dark"] {
/* 배경색 및 텍스트 색상 변경 */
body {
background-color: #121212;
color: #e0e0e0;
}
.entry-content p {
color: #e0e0e0 !important; /* 원하는 밝은 색상으로 변경 */
}
/* 헤더 링크 색상 변경 */
#header h1 a,
#header .mobile-menu span,
#header .mobile-menu:before,
#header .mobile-menu:after {
color: #ffffff;
/* background-color: #ffffff; */
}
/* 네비게이션 메뉴 색상 변경 */
#gnb ul li a {
color: #ffffff;
}
/* 컨텐츠 영역 배경 및 텍스트 색상 변경 */
#content .inner,
.entry-content {
background-color: #121212;
color: #e0e0e0;
}
a:hover {
color: #636363;
}
/* 버튼 및 폼 요소 색상 변경 */
.btn,
input,
textarea,
select {
background-color: #1f1f1f;
color: #e0e0e0;
border: 1px solid #333333;
}
/* 테두리 색상 변경 */
hr,
.pagination a,
.pagination .prev,
.pagination .next {
border-color: #333333;
}
/* 기타 필요한 요소들의 색상 변경 */
.post-item,
.cover-thumbnail-list ul li a,
.cover-masonry ul li a,
.cover-list ul li a,
.related-articles ul li a {
/* background-color: #1f1f1f; */
color: #e0e0e0;
}
/* 기존 box-shadow 설정을 다크 모드에 맞게 변경 */
.post-item a,
.cover-thumbnail-list ul li a,
.cover-masonry ul li a,
.cover-list ul li a,
.related-articles ul li a,
.tags .items a {
color: #e0e0e0;
background-color: #1f1f1f;
box-shadow: -10px -10px 30px rgba(255, 255, 255, 0.05),
10px 10px 30px rgba(0, 0, 0, 0.9);
}
.post-item {
overflow: visible;
/* 기타 속성들 */
}
/* ... 기타 요소들은 개발자 모드에서 태그 확인해가며 부족한 부분 채워넣는다.*/
}
이와 같이 data-theme="dark"
속성을 기준으로 스타일을 정의하면 다크 모드 전환이 간편해진다.
사용자 설정을 위한 다크 모드 토글 스위치 추가
사용자가 직접 다크 모드를 설정할 수 있도록 화면에 토글 스위치를 추가한다. 이 스위치는 화면 우측 하단에 고정된다.
토글 스위치 HTML 코드
위 코드에서 input과 label로 구성된 토글 스위치를 생성한다. label
안의 아이콘은 Font Awesome을 통해 다크 모드일 때 fa-moon
(달) 아이콘, 라이트 모드일 때 fa-sun
(태양) 아이콘으로 변경된다.
토글 스위치 스타일링
토글 스위치가 우측 하단에 고정되어 보이도록 스타일을 설정하고, 선택에 따라 손잡이와 배경색이 변경되도록 한다.
.mode-toggle {
position: fixed;
bottom: 20px;
right: 20px;
cursor: pointer;
z-index: 1000;
}
#mode-switch {
display: none;
}
.mode-toggle label {
position: relative;
display: block;
width: 50px;
height: 24px;
background-color: #ccc;
border-radius: 12px;
transition: background-color 0.3s;
}
.mode-toggle label .switch-icon {
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background-color: white;
border-radius: 50%;
transition: transform 0.3s;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
#mode-switch:checked + label {
background-color: #4e4e4e;
}
#mode-switch:checked + label .switch-icon {
transform: translateX(26px);
}
이 스타일은 기본 배경 색상을 설정하고, 스위치가 켜질 때마다 배경 색상과 아이콘 위치가 변경되도록 설정한다.
다크 모드 토글 기능 구현하기
사용자가 다크 모드를 선택하면 `localStorage`에 해당 설정을 저장해 페이지 전환이나 새로고침에도 설정이 유지될 수 있도록 한다. 또한, 처음 페이지 로드 시에는 사용자의 시스템 설정을 우선 적용하여 시스템 다크 모드 설정을 따르도록 한다.
<script>
document.addEventListener('DOMContentLoaded', function () {
const modeSwitch = document.getElementById('mode-switch');
const switchIcon = document.querySelector('.switch-icon i');
const userPreference = localStorage.getItem('theme');
const systemPreference = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
const initialMode = userPreference || systemPreference;
document.documentElement.setAttribute('data-theme', initialMode);
modeSwitch.checked = (initialMode === 'dark');
// 초기 아이콘 설정
if (initialMode === 'dark') {
switchIcon.classList.remove('fa-sun');
switchIcon.classList.add('fa-moon');
} else {
switchIcon.classList.remove('fa-moon');
switchIcon.classList.add('fa-sun');
}
modeSwitch.addEventListener('change', function () {
const theme = this.checked ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
// 아이콘 변경
if (theme === 'dark') {
switchIcon.classList.remove('fa-sun');
switchIcon.classList.add('fa-moon');
} else {
switchIcon.classList.remove('fa-moon');
switchIcon.classList.add('fa-sun');
}
});
});
</script>
동작 방식 설명
1. 초기 모드 설정: 페이지가 로드될 때 로컬 저장소에서 사용자 설정을 확인한다. 설정이 없다면 시스템 설정을 기준으로 초기 모드를 설정한다.
2. 아이콘 설정: 현재 모드에 따라 토글 스위치 아이콘을 `fa-sun`(라이트 모드) `또는 fa-moon`(다크 모드)로 표시한다.
3. 모드 전환: 스위치를 클릭하면 `data-theme` 속성이 변경되고, 변경된 설정을 로컬 저장소에 저장한다. 이후 아이콘도 즉시 업데이트된다.
또한 페이지 간 이동 시 CSS 적용 시간 차 문제로 잠깐동안 라이트 모드였다 다크 모드로 전환되어 깜박이는 현상을 방지하기 위해,
`head`에 다음 코드를 추가한다.
<script>
(function() {
const userPreference = localStorage.getItem('theme');
const systemPreference = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
const initialMode = userPreference || systemPreference;
document.documentElement.setAttribute('data-theme', initialMode);
})();
</script>
최종 코드
모든 코드가 적용된 최종 버전을 확인해보자.
<head>
<!-- Font Awesome 아이콘 불러오기 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script>
(function() {
const userPreference = localStorage.getItem('theme');
const systemPreference = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
const initialMode = userPreference || systemPreference;
document.documentElement.setAttribute('data-theme', initialMode);
})();
</script>
</head>
<body>
<div class="mode-toggle">
<input type="checkbox" id="mode-switch" aria-label="다크 모드 전환" />
<label for="mode-switch">
<span class="switch-icon">
<i class="fas fa-sun"></i>
</span>
</label>
</div>
<!-- CSS -->
<style>
[data-theme="dark"] {
/* 다크 모드 스타일 */
/* ... (위에서 정의한 다크 모드 CSS) */
}
.mode-toggle {
position: fixed;
bottom: 20px;
right: 20px;
cursor: pointer;
z-index: 1000;
}
#mode-switch {
display: none;
}
.mode-toggle label {
position: relative;
display: block;
width: 50px;
height: 24px;
background-color: #ccc;
border-radius: 12px;
transition: background-color 0.3s;
}
.mode-toggle label .switch-icon {
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background-color: white;
border-radius: 50%;
transition: transform 0.3s;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
#mode-switch:checked + label {
background-color: #4e4e4e;
}
#mode-switch:checked + label .switch-icon {
transform: translateX(26px);
}
</style>
<!-- JavaScript -->
<script>
document.addEventListener('DOMContentLoaded', function () {
const modeSwitch = document.getElementById('mode-switch');
const switchIcon = document.querySelector('.switch-icon i');
const userPreference = localStorage.getItem('theme');
const systemPreference = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
const initialMode = userPreference || systemPreference;
document.documentElement.setAttribute('data-theme', initialMode);
modeSwitch.checked = (initialMode === 'dark');
if (initialMode === 'dark') {
switchIcon.classList.remove('fa-sun');
switchIcon.classList.add('fa-moon');
} else {
switchIcon.classList.remove('fa-moon');
switchIcon.classList.add('fa-sun');
}
modeSwitch.addEventListener('change', function () {
const theme = this.checked ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
if (theme === 'dark') {
switchIcon.classList.remove('fa-sun');
switchIcon.classList.add('fa-moon');
} else {
switchIcon.classList.remove('fa-moon');
switchIcon.classList.add('fa-sun');
}
});
});
</script>
</body>
이제 블로그에 다크 모드가 완벽하게 구현되었다. 기본적으로 사용자의 시스템 설정을 따르며, 선택한 모드는 로컬 저장소에 저장되어 지속적으로 유지된다.
'Development > Web (HTML, CSS)' 카테고리의 다른 글
나의 마크다운 블로그 포스트 작성 루틴 (21) | 2024.11.14 |
---|---|
티스토리에서 백틱(`)으로 인라인 코드 블록 표시하기 (6) | 2024.10.31 |
Visual Studio Code Live Server 플러그인으로 웹 개발 쉽게 하자 (0) | 2020.08.27 |
Neumorphism (뉴모피즘) CSS로 만들기 (1) | 2020.08.23 |
웹사이트 상단 진행바 넣기 / HTML 16진수 색상코드 쉽게 얻는 법 (0) | 2020.08.17 |