📌 참고
이 게시글은 [프로그래머스] 과제테스트 연습 - 고양이 사진 검색 사이트를 풀어보며 공부한 내용의 일부를 정리하고 있습니다 :)
바닐라 자바스크립트 기초에 대한 중요성을 계속해서 깨닫고 있는 요즘..
알고리즘 코딩테스트만 주구장창 준비했었지만
과제 코딩테스트도 슬슬 준비해야겠다는 생각이 들었다
대체로 바닐라 자스로만 푸는 과제코테가 많기 때문에..! 많은 공부가 될 것 같다
아직 리액트 없이 쌩 자스로 개발할 때는.. 많이 뚝딱거리지만 😥 화이팅!
[참고] prefers-color-scheme - CSS: Cascading Style Sheets | MDN
@media (prefers-color-scheme: dark) {
/* 다크모드에서 적용할 CSS 정의*/
}
@media (prefers-color-scheme: light) {
/* 라이트모드에서 적용할 CSS 정의*/
}
:root
가상선택자를 활용하면 모드에 따라 여러 element에 적용되어야 하는 CSS variable을 한꺼번에 변경할 수도 있음.header {
background-color: var(--background-color);
color: var(--font-color);
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: #000;
--font-color: white;
}
}
MediaQueryList
객체를 반환if (window.matchMedia("(min-width: 400px)").matches) {
/* 뷰포트 너비가 400px 이상일 때 실행할 코드 작성 */
}
MediaQueryList
객체의 속성
matches
: document가 현재 미디어 쿼리 문자열과 일치하면 true, 일치하지 않으면 false를 반환하는 boolean 값media
: 미디어 쿼리 문자열prefers-color-scheme
미디어 쿼리를 분석하여 사용자의 OS가 사용 중인 모드를 탐지하는데 활용
if (window.matchMedia("(prefers-color-scheme: dark")).matches) {
/* 다크모드일 경우 실행할 코드 작성 */
}
else {
/* 라이트모드일 경우 실행할 코드 작성 */
}
[참고] HTMLElement.dataset - Web API | MDN
[참고] HTML 데이터셋(Dataset, data-*) 속성의 이해
data-*
와 같이 표기하고 접근HTMLElement.dataset.속성명 = 속성값;
HTMLElement.setAttribute("data-속성명", "속성값");
HTMLElement.dataset.속성명
HTMLElement.getAttribute("data-속성명")
ex. body[data-theme="light"] { /* 라이트모드 시 실행 코드 */ }
부가 설명은 코드 주석을 참고해주세요 🙌
/* style.css */
@media (prefers-color-scheme: dark) {
body {
background-color: #000;
color: white;
}
}
@media (prefers-color-scheme: light) {
body {
background-color: white;
color: #000;
}
}
body[data-theme="dark"] {
background-color: #000;
color: white;
}
body[data-theme="light"] {
background-color: white;
color: #000;
}
/* Toggle.js */
class Toggle {
constructor({ $target }) {
// 토글 버튼의 템플릿이 될 div를 하나 생성
this.$toggle = document.createElement("div");
this.$toggle.style.cssText = "width: 150px; padding: 5px 0; margin: 10px 0; border: 1px solid gray; border-radius: 8px; text-align: center;"
this.$toggle.addEventListener("mouseover", () => {
this.$toggle.style.cursor = "pointer";
});
// 다크모드일 경우 '라이트모드로 보기', 라이트모드일 경우 '다크모드로 보기' 라고 보여줄 label을 하나 생성
this.$label = document.createElement("label");
// label과 checkbox input을 연결
this.$label.htmlFor = "check";
this.$label.addEventListener("mouseover", () => {
this.$label.style.cursor = "pointer";
});
this.$toggle.appendChild(this.$label);
// 다크모드일 경우 true, 라이트모드일 경우 false로 체크할 checkbox 타입의 input을 하나 생성
this.$input = document.createElement("input");
this.$input.type = "checkbox";
this.$input.id = "check";
this.$input.style.cssText = "display: none";
this.$toggle.appendChild(this.$input);
$target.appendChild(this.$toggle);
// OS의 다크모드 활성화 여부에 따라 label과 input의 초깃값 및 body의 data-theme 속성을 설정
let $theme = document.body.dataset.theme;
if (!$theme) {
// OS의 다크모드가 활성화되어 있는 경우
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
$theme = "dark";
this.$label.innerText = "☀ 라이트모드로 보기";
this.$input.checked = true;
}
// OS의 다크모드가 비활성화되어 있는 경우
else {
$theme = "light";
this.$label.innerText = "🌙 다크모드로 보기";
this.$input.checked = false;
}
document.body.dataset.theme = $theme;
// 윗줄의 코드를 document.body.setAttribute("data-theme", $theme); 과 같이 작성할 수도 있음
}
this.render();
}
render() {
// 토글 버튼을 클릭할 경우, checkbox input의 값에 따라 적절하게 body의 data-theme 속성 및 label 텍스트를 수정
this.$toggle.addEventListener("click", (e) => {
// 다크모드일 경우 (checkbox input의 값이 true일 경우)
if (e.target.checked) {
document.body.dataset.theme = "dark";
this.$label.innerText = "☀ 라이트모드로 보기";
}
// 라이트모드일 경우 (checkbox input의 값이 false일 경우)
else {
document.body.dataset.theme = "light";
this.$label.innerText = "🌙 다크모드로 보기";
}
// 아래와 같이 checkbox input 값 자체와 무관하게 이전 data-theme 속성을 기준으로 조건문을 작성할 수도 있음
/*
if (document.body.dataset.theme === "dark") {
document.body.dataset.theme = "light";
this.$label.innerText = "🌙 다크모드로 보기";
}
else {
document.body.dataset.theme = "dark";
this.$label.innerText = "☀ 라이트모드로 보기";
}
*/
});
}
}