본문 바로가기
👩‍💻 Programming/잡동사니

티스토리 블로그 다크 테마 적용하기!!!

by codingBear 2022. 8. 2.
728x90
반응형

 한 달 전부터 미루고 미뤄뒀던 다크 테마 적용 작업을 완료했다! 처음 계획으로는 CSS에 '.dark-mode'라는 임의의 스타일을 하나 지정해놓고 JavaScript를 활용하여 Class 선택자를 넣고 빼는 식으로 하면 간단히 되지 않을까 싶었다. 하지만 오산이었다. 스타일을 적용할 요소를 일일이 불러와 알맞은 스타일을 써넣는 식으로 작업해야 했다. 중간중간에 요소를 불러올 수 없거나 페이지가 달라지면 사라지는 요소들도 있기 때문에 if문으로 존재 여부를 확인하여 스타일을 주는 식으로 처리했다. 그리고 새로고침이 일어나도 스타일 적용이 풀리지 않게끔 localstorage에다 다크 모드 boolean 여부를 저장해둬서 body 태그가 로드되면 다크 모드 여부를 확인한 뒤 스타일을 적용하는 식으로 코드를 짰다.

 여기에 플로팅 목차 관련 코드도 추가했다. 스크롤 이벤트로 Y좌표가 일정 이상 넘어가면 게시글 상세 페이지에 플로팅 목차가 보이게 했고, 윈도우 사이즈가 일정 이하로 작아지면 플로팅 목차가 사라지도록 코드를 짰다. 필시 더 효율적이고 더 나은 방식이 있을 텐데, 오늘은 이쯤 해두고 차후에 리팩토링을 시도해봐야겠다.

 이제 햇님 달님 버튼을 눌러 라이트/다크 테마를 적용해보자!

 

※ Book Club 테마 기준으로 작성한 코드입니다. 필요하신 분은 head 태그 안에 붙여넣어 사용하시면 됩니다.

<script>
	function renderTheme() {
		// dark theme
		const darkBgColor = '#292D3E';
		const darkFontColor = '#82ddff';
		const darkBoldFontColor = '#82aaff';
		const darkFontGr = '#C3E88D';
		const darkFontYl = '#FFCB6B';
		const darkFontRed = '#F07178';
		const darkWht = '#fff';
		const darkBlk = '#676E95';
		const darkBorderSt = '2px solid #82aaff';
		// light theme
		const lightBgColor = '#fffef7';
		const lightFontColor = '#777';
		const lightContentColor = '#777';
		const lightBoldFontColor = '#333';
		const lightFontBr = '#b57614';
		const lightBorderSt = '2px solid #bdae93';

		const themeBtn = document.querySelector('.change-theme-btn');
		isDarkMode = localStorage.getItem('isDarkMode');
		
		if (+isDarkMode) {
			themeBtn.innerText = '🌞 라이트 테마'
			// entire
			document.querySelector('body').classList.add('dark-mode');
			document.querySelector('#container').classList.add('dark-mode');
			document.querySelector('#container').style.backgroundColor = darkBgColor;
			document.querySelector('#container .content-wrap').classList.add('dark-mode');
			// header
			document.querySelector('#header').classList.add('dark-mode');
			document.querySelector('#header').style.borderBottom = darkBorderSt;
			document.querySelector('#header h1').style.backgroundColor = darkBgColor;
			document.querySelector('#header h1 a').style.color = darkBoldFontColor;
			document.querySelector('#header').style.backgroundColor = darkBgColor;
			document.querySelector('.search').style.backgroundColor = darkBgColor;
			document.querySelectorAll('#gnb ul li a').forEach(el => el.style.color = darkBoldFontColor);
			// sidebar
			document.querySelector('#aside').style.backgroundColor = darkBgColor;
			document.querySelector('.theme-wrap').style.border = darkBorderSt;
			document.querySelector('.tt_category').style.border = darkBorderSt;
			document.querySelectorAll('.sidebar ul li a').forEach( el => el.style.color = darkFontColor)
			document.querySelector('.sidebar .sidebar-2').style.borderTop = darkBorderSt;
			document.querySelectorAll('.sidebar h2').forEach(el => el.style.color = darkBoldFontColor);
			document.querySelectorAll('.sidebar .tab-ui h2 a').forEach(el => el.style.color = darkBoldFontColor);
			document.querySelector('.sidebar .count h2').style.borderTop = darkBorderSt;
			document.querySelectorAll('.sidebar .count p').forEach(el => el.style.color = darkFontRed);
			document.querySelector('.sidebar .count .total').style.color = darkFontGr;
			document.querySelectorAll('.tab-list ul li a img').forEach( el => el.style.border = darkBorderSt)
			// main
			if (document.querySelector('.post-header h1 em') !== null) {
				document.querySelector('.post-header h1 em').style.color = darkFontYl;
			}
			document.querySelectorAll('.post-item .title').forEach( el => el.style.color = darkBoldFontColor)
			document.querySelectorAll('.post-item .excerpt').forEach( el => el.style.color = darkFontColor)
			document.querySelectorAll('.post-item .meta').forEach( el => el.style.color = darkFontColor)
			document.querySelectorAll('.pagination a').forEach( el => el.style.color = darkBlk)
			// footer
			document.querySelector('#footer').classList.add('dark-mode');
			document.querySelector('#footer').style.borderTop = darkBorderSt;
			document.querySelectorAll('#footer p').forEach( el => el.style.color = darkFontColor)
			// detail
			document.querySelectorAll('.entry-content a').forEach( el => el.style.color = darkBoldFontColor)
			document.querySelectorAll('.og-title').forEach( el => el.style.color = darkBoldFontColor)
			document.querySelectorAll('.og-desc').forEach( el => el.style.color = darkWht)
			document.querySelectorAll('.og-host').forEach( el => el.style.color = darkWht)
			document.querySelectorAll('.entry-content p').forEach( el => el.style.color = darkWht)
			document.querySelectorAll('.entry-content p span').forEach( el => el.style.color = darkWht)
			document.querySelectorAll('.entry-content h2 b').forEach( el => el.style.color = darkWht)
			document.querySelectorAll('.entry-content h3 b').forEach( el => el.style.color = darkWht)
			document.querySelectorAll('.entry-content ul li').forEach( el => el.style.color = darkWht)
			document.querySelectorAll('.another_category_color_gray *').forEach( el => el.setAttribute('style', `color: ${darkFontColor} !important`))
			const detailH4 = document.querySelector('.another_category_color_gray h4')
			if (detailH4 !== null) {
				document.querySelectorAll('.another_category_color_gray h4').forEach( el => el.setAttribute('style', `color: ${darkBoldFontColor} !important`))
				document.querySelectorAll('.another_category_color_gray h4 a').forEach( el => el.setAttribute('style', `color: ${darkBoldFontColor} !important`))
			}
			document.querySelectorAll('.tags a').forEach( el => el.style.color = darkWht)
			document.querySelectorAll('.related-articles ul li a').forEach( el => el.style.color = darkFontColor)
			document.querySelectorAll("#tt-body-page blockquote[data-ke-style='style1']").forEach( el => el.style.color = darkWht)
			document.querySelectorAll("#tt-body-page table[data-ke-style] td").forEach( el => el.style.color = darkWht)
			document.querySelectorAll(".entry-content ol li").forEach( el => el.style.color = darkWht)
			document.querySelectorAll("#tt-body-page blockquote").forEach( el => el.style.color = darkWht)
			document.querySelectorAll("#tt-body-page h2[data-ke-size], #tt-body-page h3[data-ke-size], #tt-body-page h4[data-ke-size]").forEach( el => el.style.color = darkWht)
			// detail btn
			const replyBtn = document.querySelector('.comment-form .submit button')
			if (replyBtn !== null && document.querySelector('.comments h2 .count') !== null) {
				replyBtn.id = 'reply-btn'
				document.querySelector('.comments h2 .count').setAttribute('style', `color: ${darkFontYl} !important`)
			}
			// toc
			document.querySelector('.book-toc').style.border = darkBorderSt;
		} else {
			themeBtn.innerText = '🌜 다크 테마'
			// entire
			document.querySelector('body').classList.remove('dark-mode');
			document.querySelector('#container').classList.remove('dark-mode');
			document.querySelector('#container').style.backgroundColor = lightBgColor;
			document.querySelector('#container .content-wrap').classList.remove('dark-mode');
			// header
			document.querySelector('#header').classList.remove('dark-mode');
			document.querySelector('#header').style.borderBottom = lightBorderSt;
			document.querySelector('#header h1').style.backgroundColor = lightBgColor;
			document.querySelector('#header h1 a').style.color = lightBoldFontColor;
			document.querySelector('#header').style.backgroundColor = lightBgColor;
			document.querySelector('.search').style.backgroundColor = lightBgColor;
			document.querySelectorAll('#gnb ul li a').forEach(el => el.style.color = lightBoldFontColor);
			// sidebar
			document.querySelector('#aside').style.backgroundColor = lightBgColor;
			document.querySelector('.theme-wrap').style.border = lightBorderSt;
			document.querySelector('.tt_category').style.border = lightBorderSt;
			document.querySelectorAll('.sidebar ul li a').forEach( el => el.style.color = lightFontColor)
			document.querySelector('.sidebar .sidebar-2').style.borderTop = lightBorderSt;
			document.querySelectorAll('.sidebar h2').forEach(el => el.style.color = lightBoldFontColor);
			document.querySelectorAll('.sidebar .tab-ui h2 a').forEach(el => el.style.color = lightBoldFontColor);
			document.querySelector('.sidebar .count h2').style.borderTop = lightBorderSt;
			document.querySelectorAll('.sidebar .count p').forEach(el => el.style.color = lightFontColor);
			document.querySelector('.sidebar .count .total').style.color = lightFontBr;
			document.querySelectorAll('.tab-list ul li a img').forEach( el => el.style.border = lightBorderSt)
			// main
			if (document.querySelector('.post-header h1 em') !== null) {
				document.querySelector('.post-header h1 em').style.color = lightFontBr;
			}
			document.querySelectorAll('.post-item .title').forEach( el => el.style.color = lightBoldFontColor)
			document.querySelectorAll('.post-item .excerpt').forEach( el => el.style.color = lightFontColor)
			document.querySelectorAll('.post-item .meta').forEach( el => el.style.color = lightFontColor)
			document.querySelectorAll('.pagination a').forEach( el => el.style.color = darkBlk)
			// footer
			document.querySelector('#footer').classList.remove('dark-mode');
			document.querySelector('#footer').style.borderTop = lightBorderSt;
			document.querySelectorAll('#footer p').forEach( el => el.style.color = lightFontColor)
			// detail
			document.querySelectorAll('.entry-content a').forEach( el => el.style.color = lightFontBr)
			document.querySelectorAll('.og-title').forEach( el => el.style.color = lightBoldFontColor)
			document.querySelectorAll('.og-desc').forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll('.og-host').forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll('.entry-content p').forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll('.entry-content p span').forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll('.entry-content h2 b').forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll('.entry-content h3 b').forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll('.entry-content ul li').forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll('.another_category_color_gray *').forEach( el => el.setAttribute('style', `color: ${lightFontColor} !important`))
			const detailH4 = document.querySelector('.another_category_color_gray h4')
			if (detailH4 !== null) {
				document.querySelectorAll('.another_category_color_gray h4').forEach( el => el.setAttribute('style', `color: ${lightBoldFontColor} !important`))
				document.querySelectorAll('.another_category_color_gray h4 a').forEach( el => el.setAttribute('style', `color: ${lightBoldFontColor} !important`))
			}
			document.querySelectorAll('.tags a').forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll('.related-articles ul li a').forEach( el => el.style.color = lightFontColor)
			document.querySelectorAll("#tt-body-page blockquote[data-ke-style='style1']").forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll("#tt-body-page table[data-ke-style] td").forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll(".entry-content ol li").forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll("#tt-body-page blockquote").forEach( el => el.style.color = lightContentColor)
			document.querySelectorAll("#tt-body-page h2[data-ke-size], #tt-body-page h3[data-ke-size], #tt-body-page h4[data-ke-size]").forEach( el => el.style.color = darkWht)
			// detail btn
			const replyBtn = document.querySelector('.comment-form .submit button')
			if (replyBtn !== null && document.querySelector('.comments h2 .count') !== null) {
				replyBtn.removeAttribute('id')
				document.querySelector('.comments h2 .count').setAttribute('style', `color: ${lightFontBr} !important`)
			}
		  // toc
			document.querySelector('.book-toc').style.border = lightBorderSt;
		}
			document.querySelector('.pagination .selected').style.color = darkFontRed;
	}

	function handleChangeTheme(theme) {
		if (theme === 'light') {
			localStorage.setItem('isDarkMode', 0);
		} else {
			localStorage.setItem('isDarkMode', 1);
		}
		renderTheme();
	}

	function handleThemeBtn() {
		const themeBtn = document.querySelector('.change-theme-btn');
		isDarkMode = localStorage.getItem('isDarkMode');

		+isDarkMode ? handleChangeTheme('light') : handleChangeTheme('dark');
	}

	window.addEventListener('scroll', () => { 
		const bookToc = document.querySelector('.book-toc');
		const toc = document.querySelector('#toc');
		const coordY = window.scrollY;
		const width = window.innerWidth;

		if (width > 1365 && coordY > 300 && toc.innerHTML !== '') {
			bookToc.style.display = 'block'
		} else {
			bookToc.style.display = 'none'
		}
	});

	window.addEventListener('resize', () => {
		const bookToc = document.querySelector('.book-toc');
		const toc = document.querySelector('#toc');
		const coordY = window.scrollY;
		const width = window.innerWidth;
		
		if (width > 1365 && coordY > 300 && toc.innerHTML !== '') {
			bookToc.style.display = 'block'
		} else {
			bookToc.style.display = 'none'
		}
	});
</script>
728x90
반응형

댓글