일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 클라우드 및 devops
- private image registry
- https
- 직무탐방
- 티스토리 스킨
- Harbor
- 기술탐방
- 다크 모드
- Terraform
- 소프트웨어 엔지니어링
- 시작글
- SW개발
- CI/CD
- IT
- 소프트웨어엔지니어링
- IAC
- docker compose
- 백엔드 개발
- OpenSSL
- cloud
- frontend
- 풀스택 개발자
- Programming Language
- docker
- 임베디드 개발
- Infrastructure
- devops
- TSL
- it 인프라 및 운영
- AWS
- Today
- Total
방구석 IT
티스토리 기본 스킨(#2)에 다크 모드 적용하기 본문
블로그에 올라온 글을 볼 때 화면이 너무 밝아서 눈이 아프다는 피드백을 받았다.
지금 사용하는 기본 스킨의 구성이 너무 마음에 들지만 다크 모드가 기본적으로 지원하지 않기 때문에 직접 다크 모드 기능을 추가해 보고자 한다. 스킨에 대한 저작권이 티스토리에 있기에 추가되는 내용만 작성하고 전체 코드와 파일은 첨부하기 힘들다.
목표
티스토리 기본 스킨(#2)에 다크 모드 기능 추가하기
먼저 다크 모드에 필요한 조건을 정리해보자.
조건
- 다크 모드 활성/비활성 버튼 생성
- 다크 모드 시 배경은 어두워지고 글자의 색은 밝아지거나 반전
- 프로필 이미지, 아이콘, 배너 이미지, 게시글 이미지 등과 같은 요소는 다크 모드에 영향을 받지 않음
- 다크 모드 여부는 접속자 개인의 기본 환경값과 동일하게 자동 적용
- 지정한 다크 모드 재접속 시 유지
- 그 외 일관적이지 않거나 어색한 디자인(색감, 구성) 수정
1. HTML 수정
우선 HTML에 다크 모드 전환에 필요한 버튼을 추가해 주도록 한다. 버튼은 특정 div 내에 있을 필요가 없기 때문에 body 태그 내에 바로 위치해 준다.
<body id="tt-body-page" class="">
<button class="dark-mode-toggle">🌙 다크모드</button>
...
</body>
2. CSS 수정
기존 스킨에서 다크 모드로 변경할 요소들을 모두 확인 후 다크 모드에서 변경되어야 할 class들에 추가적인 값을 추가했다.
먼저 다크 모드 버튼의 속성을 추가했다.
/* 버튼 스타일 */
.dark-mode-toggle {
position: fixed;
bottom: 15px;
right: 15px;
background: #333;
color: #fff;
border: none;
padding: 10px;
border-radius: 5px;
cursor: pointer;
z-index: 9999;
}
/* 버튼에 마우스 호버 효과 */
.dark-mode-toggle:hover {
background: #555;
}
/* 구독하기 버튼이 있을 때 다크모드 버튼 위치 조정 */
body.has-btn-tool .dark-mode-toggle {
bottom: 60px; /* 구독 버튼 위로 이동 */
}
기본 스킨이 반응형으로 만들어져 있고 PC 환경에서 구독하기 툴바가 존재하기 때문에 겹치지 않도록 해준다.
다음으로 다크 모드의 기본 스타일을 잡아주자.
/* 다크모드 스타일 */
body.dark-mode {
background-color: #121212;
color: #e0e0e0;
}
/* 링크 색상 조정 */
body.dark-mode .link_post:hover {
color: #6bacce;
}
body.dark-mode .area_profile .link_post:hover {
color: initial !important; /* 기본 색상 유지 */
}
/* 본문 영역 */
body.dark-mode .area_view {
filter: invert(1);
background-color: #121212;
}
/* 게시글 타이틀 */
body.dark-mode .area_title {
border-bottom: 1px solid #333;
}
다크 모드 색상을 지정하고 기본 요소들을 확인해 봤다.
배너나 프로필 등은 변동이 없어야 하기에 기존 설정을 유지하도록 한다.
다음으로 다크 모드가 반영될 class와 반영이 되면 안 될 class를 찾아서 작성한다.
/* article_skin 내부 글씨와 그 외 반전 */
body.dark-mode .article_skin,
body.dark-mode .contents_style,
body.dark-mode .tt-comment-cont,
body.dark-mode .info_post,
body.dark-mode .tt-box-account,
body.dark-mode .tt-box-textarea,
body.dark-mode .txt_like,
body.dark-mode .container_postbtn .txt_state,
body.dark-mode .link_cate,
body.dark-mode .tit_category,
body.dark-mode .selected,
body.dark-mode .link_post:hover {
filter: invert(1);
}
/* 반전 제외할 요소들 */
body.dark-mode .article_skin img,
body.dark-mode .article_skin video,
body.dark-mode .article_skin iframe,
body.dark-mode .article_skin .thumb_profile,
body.dark-mode .article_skin .tt_wrap_thumb,
body.dark-mode .article_skin .list_tag,
body.dark-mode .area_view a {
filter: invert(1);
}
본래 다크 모드는 색상 팔레트나 지정 값을 통해 구현하지만 수작업으로 지정하기는 작업 소요가 크기 때문에 filter: invert(1)로 색상 반전 효과를 사용했다. 반전이 반영되야 할 class를 먼저 적용하고 아닌 클래스를 찾아 반전 효과를 되돌리도록 한다.
invert를 사용하니 텍스트 드래그 시 선택된 영역의 기본 효과인 파란 배경에 하얀 글씨가 반전되어 누런색이 되어버렸다.
선택된 영역이 직관적이고 다크 모드와 어울리도록 회색으로 지정해 주자. 반전 효과가 적용되고 있기 때문에 글씨는 흰색의 반대인 검정으로 한다.
/* 다크모드에서 선택된 텍스트의 색상을 고정 */
body.dark-mode *::selection {
background: #a0a0a0; /* 다크모드에서 선택 시 배경색 (밝은 회색) */
color: #000; /* 선택된 텍스트 색상을 검은색으로 고정 */
}
이로써 HTML과 CSS 작업이 끝났다. CSS 코드들은 기존 코드의 제일 끝에 추가해 주면 된다.
3. Javascript 수정
이제 다크 모드 기능을 실행시킬 js 코드를 작성하자.
먼저 버튼을 누르면 모드가 변경되도록 토글 버튼으로 만들어준다.
...
(function() {
const toggleButton = document.createElement('button');
toggleButton.classList.add('dark-mode-toggle');
toggleButton.textContent = '🌙 다크모드';
document.body.appendChild(toggleButton);
// 로컬 스토리지에서 다크모드 설정 가져오기
if (localStorage.getItem('dark-mode') === 'enabled') {
document.body.classList.add('dark-mode');
toggleButton.textContent = '☀️ 라이트모드';
}
// 버튼 클릭 시 다크모드 토글
toggleButton.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
if (document.body.classList.contains('dark-mode')) {
localStorage.setItem('dark-mode', 'enabled');
toggleButton.textContent = '☀️ 라이트모드';
} else {
localStorage.setItem('dark-mode', 'disabled');
toggleButton.textContent = '🌙 다크모드';
}
});
})();
...
다크 모드 활성 여부를 브라우저의 로컬 스토리지에서 가져와 반영한다. 토글로 현재 모드에 따라 버튼이 활성화되고, 버튼을 누르면 dark-mode class가 enabled/disabled 되도록 한다.
PC 환경에서 구독하기 툴바랑 겹치는 문제를 방지하기 위해 툴바를 피해서 구독하기 버튼이 생성되도록 함수를 추가해 준다.
...
(function() {
const toggleButton = document.querySelector('.dark-mode-toggle');
function updateDarkModeButtonPosition() {
if (document.querySelector('.btn_tool')) {
document.body.classList.add('has-btn-tool'); // 구독 버튼이 있으면 클래스 추가
} else {
document.body.classList.remove('has-btn-tool'); // 없으면 클래스 제거
}
}
// 페이지 로드 시 버튼 위치 확인
updateDarkModeButtonPosition();
// DOM 변화 감지하여 실시간으로 확인 (구독 버튼이 동적으로 추가될 수도 있음)
const observer = new MutationObserver(updateDarkModeButtonPosition);
observer.observe(document.body, { childList: true, subtree: true });
})();
이렇게 작성이 완료된 코드는 다운로드한 기존 스킨의 script.js의 맨 끝에 추가해 주고, 블로그 스킨 편집에서 재업로드 해주도록 한다. HTML과 CSS는 바로 작성해 준다.
4. 결과
결과적으로 기존에 사용하는 스킨의 구성을 변형하기보다는 추가하기만 해서 반응형이 유지되도록 다크 모드를 구현했다.
구현 방법으로 색상 반전을 채택하는 바람에 원하는 색이 안된다든지 CSS가 깨지는 등의 문제점이 있었다. 또한 기존 스킨의 구조를 하나하나 뜯어보며 수정해야 했기에 역시 한땀 한땀 CSS 따는 건 번거로운 일이었다. 여러 환경에서 반응형 페이지의 동작을 확인하고 구독 툴바와 같은 구성에 맞게 수정하는 작업도 있었다.
처음에 희망하고자 하는 조건은 모두 충족시켰으나, 몇 가지 이슈가 남았다.
마찬가지로 색상 반전 기반이기 때문에 차후에 포스트를 작성하며 강조색을 사용할 때는 다크 모드 적용 시 이상한 색이 될 수도 있다. 또한 invert(1)로 구현한 탓인지 다크 모드에서 화면을 자세히 보면 배경이 자글자글거리는 랜더링 아티팩트가 발생하는 것 같다. invert의 실시간 색상 반전의 문제, 내 모니터 문제, 요소들 간의 충돌의 문제 중 하나로 추정하고 있다. 이 이슈들은 나중에 해결해야 하는 상황이나 작업할 여유가 생긴다면 알아보려 한다.
참고
- CSS Docs (https://devdocs.io/css/)
이 포스트의 전체 코드의 경우, 원본 스킨의 저작권이 티스토리에 있기에 GitHub 링크를 첨부하지 않습니다.