
CSS 시각 효과 - 그림자(Shadow)와 필터(Filter)로 2D 화면에 3D 공간감을 불어넣다
우리가 매일 쳐다보는 모니터나 스마트폰 화면은 물리적으로 완벽하게 평평한 2D(2차원) 평면입니다. 하지만 애플(Apple)의 iOS UI나 구글의 머티리얼 디자인(Material Design)을 보면, 버튼들이 공중에 살짝 떠 있는 것 같기도 하고, 뒤에 있는 배경이 반투명한 유리창(Glassmorphism)을 댄 것처럼 은은하게 번져 보이기도 합니다. 어떻게 물리적인 평면 디스플레이에서 이런 깊이감(Depth)과 3차원적 질감을 느끼게 할 수 있을까요? 그것은 바로 프론트엔드 개발자들이 박스 주변에 미세한 '그림자(Shadow)'를 흩뿌리고, 요소 전체에 포토샵 뺨치는 '필터(Filter)' 마법을 걸어 사용자의 뇌에 착시 현상을 일으키기 때문입니다. 아무리 뼈대를 Grid와 Flex로 완벽하게 짰어도, 결국 이 빛과 그림자의 조절 실패하면 그 웹사이트는 90년대 파워포인트 슬라이드처럼 극도로 촌스러워집니다.
이번 글에서는 주니어 개발자들의 새카만 떡보정 그림자를 우아한 멀티 섀도우(Multi-shadow)로 업그레이드하는 실무 공식과, 투명한 PNG 이미지의 외곽선만 귀신같이 따라가는 drop-shadow 필터, 그리고 모던 UI의 핵심인 backdrop-filter 글래스모피즘(유리 질감) 렌더링 원리까지 상세히 알아보겠습니다.
1. 촌스러움과 우아함의 차이: box-shadow 심층 분석
box-shadow 속성은 요소의 테두리 바깥쪽(또는 안쪽)으로 그림자를 투사합니다. 문법은 수평이동(X) 수직이동(Y) 흐림(Blur) 확산(Spread) 색상(Color) 순서로 작성합니다. 하지만 초보자들은 보통 box-shadow: 5px 5px 5px black; 같은 끔찍한 코드를 작성합니다. 이렇게 만들어진 시꺼먼 연탄재 같은 그림자는 UI를 싸구려로 만드는 주범입니다.
💡 실무 정석: 멀티 섀도우 (Multi-shadow) 겹쳐 바르기
현실 세계의 빛은 하나의 광원에서만 오지 않습니다. 태양 직사광선이 있으면 주변 벽에 반사된 간접광도 존재하죠. 따라서 최고급 UI 디자이너들은 절대 그림자를 한 겹만 쓰지 않습니다. 아주 연하고 흐린(Blur가 넓은) 거대한 배경 그림자와, 짧고 진한(Blur가 좁은) 밀착 그림자를 쉼표(,)로 연결하여 여러 겹(Layer) 겹쳐 바르는 '멀티 섀도우' 기법을 사용합니다.
/* 애플(Apple) 스타일의 고급스럽고 부드러운 다중 그림자 공식 */
.card-elegant {
box-shadow:
0 1px 3px rgba(0, 0, 0, 0.05), /* 1겹: 아주 짧고 옅은 밀착 그림자 */
0 10px 15px rgba(0, 0, 0, 0.05), /* 2겹: 중간 크기의 은은한 그림자 */
0 20px 25px rgba(0, 0, 0, 0.02); /* 3겹: 바닥 전체에 넓게 깔리는 분위기 그림자 */
}
추가로, inset 키워드를 맨 앞에 붙이면 그림자가 박스 바깥이 아니라 '안쪽'으로 파고들게 되어, 마치 버튼이 화면 안으로 푹 파여 눌린 듯한 음각(Neumorphism) 효과를 기가 막히게 연출할 수 있습니다.
2. 브라우저 속의 포토샵: CSS Filter (필터)
예전에는 흑백 사진을 올리려면 디자이너가 포토샵에서 채도를 빼고 다시 저장해서 서버에 업로드해야 했습니다. 이제는 CSS의 filter 속성이 브라우저 단에서 그래픽 카드를 쥐어짜며 이미지를 실시간(Real-time)으로 렌더링 보정해 줍니다.
blur(5px): 이미지를 뿌옇게 날려버립니다. 뒷배경 초점을 날리는 아웃포커싱(Depth of Field) 효과에 최고입니다.grayscale(100%): 이미지를 완전한 흑백으로 만듭니다.brightness(50%)/contrast(150%): 밝기와 대비를 조절합니다. 마우스 호버 시brightness(80%)를 주어 이미지를 살짝 어둡게 만드는 기법은 실무 인터랙션의 단골손님입니다.
3. 투명 PNG의 구세주: drop-shadow() 필터
배경이 투명한 별 모양(★) PNG 이미지에 앞서 배운 box-shadow를 주면 어떻게 될까요? 브라우저는 별 모양을 무시하고, 이미지를 감싸고 있는 투명한 '정사각형 박스' 전체 테두리에 시꺼먼 그림자를 쳐버립니다. 투명한 알파(Alpha) 채널을 전혀 인식하지 못하기 때문입니다.
이 끔찍한 사태를 구원하기 위해 존재하는 것이 바로 filter: drop-shadow(0 5px 5px rgba(0,0,0,0.5)) 입니다. 이 녀석은 GPU 가속을 활용하여 이미지의 픽셀(Pixel) 데이터를 뜯어본 뒤, 투명한 부분을 무시하고 실제 물감이 칠해진 불투명한 곡선 윤곽선을 따라 정확하게 그림자를 뿌려주는 미친 렌더링 성능을 자랑합니다. SVG 아이콘이나 누끼가 따진 PNG 이미지를 공중에 띄울 때는 무조건 이 속성을 써야 합니다.
4. 현대 UI 디자인의 정점: 글래스모피즘 (backdrop-filter)
애플 iOS의 제어 센터 창을 쓸어내리면 뒷배경의 아이콘들이 형체만 흐릿하게 남고 아름답게 뭉개집니다. 이 반투명 유리창(Frosted Glass) 질감은 2020년대 프론트엔드 UI/UX의 트렌드를 완전히 집어삼킨 '글래스모피즘(Glassmorphism)'입니다. 과거에는 이 효과를 내기 위해 꼼수 캔버스(Canvas) 코딩을 짜야 했지만, 이제는 backdrop-filter 단 한 줄로 끝납니다.
.glass-modal {
background-color: rgba(255, 255, 255, 0.3); /* 1. 박스 자체를 반투명한 흰색으로 만듦 */
backdrop-filter: blur(10px); /* 2. 박스 "뒤쪽에 깔려있는" 모든 배경 요소들을 10px만큼 뿌옇게 렌더링! */
border: 1px solid rgba(255, 255, 255, 0.5); /* 3. 유리의 반짝이는 외곽선 디테일 */
}
일반 filter: blur()가 '자기 자신'을 뿌옇게 만든다면, backdrop-filter: blur()는 '자신을 통과해서 보이는 뒷배경'만을 선택적으로 뿌옇게 렌더링하는 고난도 픽셀 셰이딩(Shading) 연산을 수행합니다. 모달 팝업창이나 상단에 고정된 스티키 헤더(Sticky Header)에 이 효과를 덧바르면, 웹사이트의 퀄리티가 갑자기 실리콘밸리 스타트업 수준으로 수직 상승하는 마법을 경험할 수 있습니다.
정리하며
이번 글에서는 평평한 브라우저 평면 위에 빛을 비추고 층(Layer)을 띄우는 box-shadow와 filter 속성들을 파헤쳐 보았습니다. 멀티 섀도우로 은은한 깊이감을 주고 글래스모피즘으로 시선을 사로잡을 수 있게 되었다면, 이제 여러분은 디자이너와 싸우지 않고도 픽셀 퍼펙트(Pixel Perfect)한 디자인을 코드로 구현할 수 있게 되었습니다. 자, 그런데 이렇게 예쁘게 만든 버튼 위로 마우스를 올렸을 때 그림자가 '팟!' 하고 눈 튀어나오게 깜빡이며 변한다면 어떨까요? 사용자의 감성은 와장창 깨져버릴 것입니다. 부드러움이 곧 고급스러움입니다. 상태 A에서 상태 B로 넘어가는 찰나의 시간을 지배하는 시간 마술사! 다음
그림자(Box-shadow)와 필터(Filter) - 평면 UI에 입체감과 감성을 불어넣다
웹 디자인 트렌드가 아무리 '플랫 디자인(Flat Design)'을 외쳐도, 우리는 물리적 현실 세계에 살고 있는 인간이기에 '입체감'과 '깊이감'을 본능적으로 편안하게 느낍니다. 화면 속 하얀 배경 위에 똑같이 하얀 버튼이 있다면, 사람들은 그것을 버튼으로 인지하지 못합니다. 하지만 그 하얀 버튼 아래에 아주 옅고 부드러운 그림자(Shadow)가 깔리는 순간, 뇌는 즉각적으로 "아! 저것은 배경보다 위로 튀어나와서 누를 수 있는 물리적 객체구나!"라고 인식하게 됩니다. 이처럼 CSS의 그림자 효과는 단순한 미적 장식이 아니라 사용자 경험(UX)을 결정짓는 강력한 인지 도구입니다. 더불어, 포토샵에서나 가능했던 이미지 흑백 처리나 블러(Blur) 효과를 브라우저 단에서 실시간으로 렌더링 해버리는 filter 속성까지! 이번 글에서는 현대 웹 UI의 품격을 수직 상승시키는 box-shadow와 filter의 완벽 가이드를 다뤄보겠습니다.
1. 입체감의 마술사: box-shadow 완전 정복
box-shadow 속성은 무려 5개(inset 포함 시 6개)의 파라미터를 한 줄에 띄어쓰기로 나열하여 작성합니다. 순서가 매우 중요합니다.
.card {
/* 순서: X축 이동 | Y축 이동 | Blur(흐림) 반경 | Spread(확장) 반경 | 색상 */
box-shadow: 0px 4px 20px -2px rgba(0, 0, 0, 0.1);
}
파라미터 상세 분석
- X축 / Y축 오프셋: 양수를 주면 우측/아래로, 음수를 주면 좌측/위로 그림자가 뻗어나갑니다. 자연스러운 빛은 보통 위에서 아래로 떨어지므로 Y축에만 양수를 주는 것이 정석입니다.
- Blur(블러) 반경: 숫자가 클수록 그림자가 뿌옇고 부드럽게 퍼집니다. 숫자가 0이면 칼로 자른 듯 날카로운 솔리드 그림자가 됩니다. (레트로 8비트 게임 UI에 제격)
- Spread(스프레드) 반경: 그림자의 '크기' 자체를 키우거나 줄입니다. 실무에서는 그림자가 너무 뚱뚱해지는 것을 막기 위해 음수값(예: -2px)을 주어 그림자를 박스 안쪽으로 쫙 조여주면서 부드럽게 퍼지게 만드는 고급 테크닉을 씁니다.
💡 실무 꿀팁: 다중 그림자와 우아한 호버(Hover) 효과
그림자는 쉼표(,)로 여러 겹을 겹칠 수 있습니다. 애플(Apple) 웹사이트처럼 극도로 부드럽고 현실적인 그림자는 보통 3겹 이상의 미세한 그림자를 중첩하여 만듭니다.
.floating-btn {
/* 기본 상태: 은은하게 깔린 그림자 */
box-shadow: 0 4px 6px rgba(0,0,0, 0.05);
transition: box-shadow 0.3s ease, transform 0.3s ease;
}
.floating-btn:hover {
/* 마우스 오버 시: Y축 이동(transform)과 함께 그림자를 넓고 흐리게 퍼뜨려 위로 붕 뜨는 착각 유도! */
transform: translateY(-5px);
box-shadow: 0 15px 25px rgba(0,0,0, 0.15);
}
2. 포토샵을 브라우저로: CSS Filter 효과
과거에는 디자이너에게 "마우스를 올리면 이미지가 흑백에서 컬러로 샥~ 바뀌게 해주세요"라고 요청하면, 디자이너가 흑백 이미지와 컬러 이미지 2장을 저장해서 줬습니다. 이제는 원본 컬러 이미지 1장만 서버에 올리고, CSS filter 하나로 끝냅니다.
실무 필수 Filter 함수 4가지
filter: grayscale(100%);: 이미지를 완벽한 흑백으로 날려버립니다. 협력사 로고들을 회색조로 통일할 때 국룰로 쓰입니다.filter: blur(5px);: 이미지를 뽀샤시하게 흐립니다. 모달(Modal) 창이 뜰 때 배경을 흐리게(블러 처리) 만들거나 로딩 중인 썸네일을 표현할 때 씁니다.filter: brightness(0.8);: 밝기를 조절합니다. 1 이하면 어두워지고 1 이상이면 밝아집니다. 이미지 호버 시rgba()Dim 처리를 대신하여brightness(0.5)로 뚝딱 어둡게 만들 때 최고입니다.filter: drop-shadow(...);:box-shadow와 비슷하지만 차원이 다릅니다. 박스의 네모난 테두리가 아니라, '투명한 배경을 가진 PNG 이미지의 실제 픽셀 형태'를 따라 정밀하게 그림자를 그려줍니다!
정리하며
box-shadow와 filter는 평범한 2D 캔버스에 Z축의 깊이감을 부여하는 마법의 가루입니다. 특히 카드가 마우스 호버 시 그림자가 넓게 퍼지며 위로 떠오르는(Floating) UI는 현대 웹 디자인의 절대적인 표준 작법입니다. 그런데, 방금 제가 '마우스를 올릴 때 부드럽게(0.3s) 그림자가 변한다'라고 무심코 지나갔죠? 상태가 팍! 하고 바뀌는 것이 아니라 시간의 흐름에 따라 스르륵 변하게 만드는 이 마취제 같은 기술이 궁금하지 않으신가요? 다음이번 포스팅에서는 CSS에 시간(Time)의 차원을 도입하는 첫걸음, "Transition: 부드러운 상태 변화의 기초"에 대해 뼈 때리게 파헤쳐 보겠습니다!
CSS 다크 모드 (Dark Mode) - 눈부심을 막는 테마 스위칭과 시스템 설정 감지의 마법
불과 몇 년 전만 해도 웹사이트에서 배경색을 하얗게, 글씨를 까맣게 쓰는 것은 너무나 당연한 진리였습니다. 하지만 애플(Apple)이 iOS와 macOS에 '다크 모드(Dark Mode)'라는 전 시스템적 흑화 테마를 도입한 이후, 전 세계의 UI 패러다임은 완전히 뒤집혔습니다. 밤에 불을 끄고 스마트폰을 보는 현대인들에게 흰색 배경의 웹사이트는 눈을 찌르는 섬광탄(Flashbang)과도 같습니다. 눈의 피로도(Eye Strain)를 줄여주고 OLED 디스플레이 기기의 배터리 수명을 극적으로 늘려주는 다크 모드는 이제 '있으면 좋은 옵션'이 아니라 프론트엔드 개발자가 무조건 구현해야 하는 '필수 접근성(A11y) 요건'이 되었습니다. 과거에는 다크 모드를 구현하기 위해 HTML 태그 곳곳에 자바스크립트로 일일이 클래스를 붙였다 뗐다 하는 무식한 막노동을 벌이곤 했습니다. 하지만 현대 CSS는 운영체제(Windows, Mac)의 다크 모드 스위치를 귀신같이 감지하는 미디어 쿼리(Media Query)부터, 단 한 줄의 자바스크립트 토글링으로 사이트 전체의 테마를 뒤엎어버리는 'CSS 사용자 지정 속성(Variables)' 아키텍처를 제공합니다. 이번 글에서는 OS의 테마를 도청하는 prefers-color-scheme의 원리와, 색상 하드코딩의 늪을 탈출하여 가장 완벽하고 확장성 높은 다크 모드 시스템을 설계하는 실무 노하우에 대해 다뤄보겠습니다.
1. 운영체제(OS)의 속마음을 읽어라: prefers-color-scheme
모바일 반응형 웹을 배울 때 우리는 @media (max-width: 768px)를 사용하여 '화면의 너비'를 감지했습니다. 놀랍게도 미디어 쿼리는 너비뿐만 아니라 현재 사용자의 스마트폰이나 윈도우 OS가 다크 모드 환경인지, 라이트 모드 환경인지까지 감지해 내는 무서운 염탐꾼 역할을 수행할 수 있습니다. 그 핵심 키워드가 바로 prefers-color-scheme입니다.
/* 기본 스타일: 라이트 모드 (낮) */
body {
background-color: #ffffff;
color: #333333;
}
/* 💡 사용자의 OS가 '다크 모드'로 설정되어 있을 때만 이 코드를 덮어씌워라! */
@media (prefers-color-scheme: dark) {
body {
background-color: #121212; /* 눈이 편안한 다크 그레이 배경 */
color: #e0e0e0; /* 너무 쨍하지 않은 연한 회색 글씨 */
}
}
이 방식을 사용하면 자바스크립트를 단 한 줄도 쓰지 않고도, 사용자가 아이폰 제어 센터에서 다크 모드 버튼을 껐다 켤 때마다 실시간으로 웹사이트의 색상이 마법처럼 반전되는 것을 볼 수 있습니다.
2. 실무 1티어 설계: CSS Variables (변수) 기반의 테마 시스템
위의 방식은 작고 단순한 웹사이트에서는 잘 먹히지만, 수백 개의 버튼과 카드 UI가 얽혀있는 대형 실무 프로젝트에서는 끔찍한 재앙을 낳습니다. @media dark 블록 안에 수천 줄의 색상 덮어쓰기 코드를 다시 작성해야(중복) 하기 때문입니다. 이를 구원할 단 하나의 완벽한 아키텍처는 이전 포스팅에서 배웠던 CSS Variables(사용자 지정 속성)를 적극 도입하는 것입니다.
변수 딕셔너리로 색상을 추상화(Abstraction)하라
절대로 .btn { color: black; } 처럼 하드코딩하지 마십시오. 모든 색상을 :root에 변수로 등록하고, 컴포넌트들은 변수 이름만 가져다 쓰도록(참조) 만들어야 합니다.
/* 1. 글로벌 테마 금고 (기본 라이트 모드 세팅) */
:root {
--bg-primary: #ffffff;
--text-primary: #222222;
--card-surface: #f5f5f5;
}
/* 2. 자바스크립트가 <body> 태그에 class="dark-theme"을 달아줄 때 변수값들만 싹 다 교체! */
body.dark-theme {
--bg-primary: #181818;
--text-primary: #efefef;
--card-surface: #2d2d2d;
}
/* 3. 컴포넌트는 오직 '변수 이름'만 바라본다! (테마가 바뀌든 말든 알 바 아님) */
.card-component {
background-color: var(--card-surface);
color: var(--text-primary);
}
이 아키텍처의 위대함은, 사용자가 화면 우측 상단의 '달/태양 아이콘(토글 버튼)'을 클릭했을 때 자바스크립트로 body.classList.toggle('dark-theme') 단 한 줄만 실행해 주면, 수만 개의 DOM 요소들이 바라보고 있는 변수 통로의 근원지 값이 통째로 교체되면서 브라우저 전체가 0.01초 만에 다크 모드로 리렌더링 된다는 점입니다. 유지보수의 끝판왕 설계입니다.
3. 디테일의 악마: 다크 모드에서의 눈부심 방지 팁
배경만 까맣게 칠했다고 훌륭한 다크 모드가 되는 것은 아닙니다. 진정한 고수들은 두 가지 치명적인 디테일을 놓치지 않습니다.
① 완전한 블랙(#000000)을 피하라
다크 모드 배경색으로 순수한 #000000 검은색을 쓰고 글씨를 #ffffff 완전한 흰색을 쓰면, 너무 강력한 명암비(Contrast) 때문에 스크롤할 때 글씨가 번져 보이는 '할레이션(Halation) 현상'이 발생해 눈을 심하게 피로하게 만듭니다. 구글의 머티리얼 디자인 가이드라인은 다크 모드 배경으로 #121212나 #181818 같은 부드러운 다크 그레이를 사용하라고 강력히 권고합니다.
② 이미지 디밍 (Dimming) 필터
배경은 어두워졌는데, 쇼핑몰에 등록된 밝고 화사한 흰색 배경의 상품 사진(Image)들이 그대로 출력되면 그 사진 자체가 섬광탄처럼 눈을 부시게 만듭니다. 고수들은 다크 모드가 켜졌을 때 CSS filter 속성을 이용해 이미지들의 눈부심을 강제로 낮춰버립니다.
body.dark-theme img {
/* 밝기를 80%로 줄이고, 약간 탁해지는 걸 막기 위해 대비(contrast)를 살짝 올려준다 */
filter: brightness(0.8) contrast(1.1);
}
정리하며
이번 글에서는 OS 레벨의 테마를 감지하는 미디어 쿼리와, CSS 변수(Variables)를 뼈대로 삼아 단 한 번의 토글로 수만 개의 색상을 뒤집는 완벽한 다크 모드 아키텍처에 대해 상세히 살펴보았습니다. 극단적인 블랙을 피하고 이미지 디밍 필터까지 챙긴다면 여러분의 다크 모드는 애플이나 구글 앱 못지않은 럭셔리한 퀄리티를 자랑하게 될 것입니다. 자, 디자인과 레이아웃, 심지어 모드 변경까지 완성되었습니다. 그런데 브라우저에서 '스크롤'을 내릴 때마다 뚝뚝 끊기거나, 틱톡/유튜브 쇼츠처럼 한 틱을 넘기면 다음 동영상으로 자석처럼 '찰칵!' 하고 달라붙게(Snap) 만들려면 어떻게 해야 할까요? 복잡한 JS 스크롤 플러그인들을 모조리 멸종시켜버린 CSS의 기적! 다음이번 포스팅에서는 "CSS Scroll Snap과 Behavior: 자바스크립트 없이 구현하는 틱톡(TikTok) 스크롤과 스무스 앵커링"에 대해 상세히 자세히 알아보겠습니다.
다크 모드(Dark Mode) 완벽 구현 가이드 - 트렌드를 넘어선 필수 스펙
수년 전만 해도 화면을 까맣게 반전시키는 '다크 모드(Dark Mode)'는 일부 개발자들만의 마이너 한 취향이었습니다. 하지만 스마트폰의 OLED 디스플레이 보급으로 인한 배터리 절약 이슈와 시력 보호 열풍이 맞물리면서, 오늘날 다크 모드는 사용자가 웹사이트를 평가하는 '기본적인 UX 품질 척도'이자 필수 스펙으로 자리 잡았습니다. 다크 모드가 없으면 촌스럽고 배려 없는 사이트로 낙인찍히기 십상입니다. 그렇다면 다크 모드는 어떻게 만들까요? 검은 배경용 HTML 파일과 하얀 배경용 HTML 파일을 두 개 만들어야 할까요? 아닙니다! 우리는 직전 포스팅에서 완벽한 무기인 'CSS 변수(Variables)'를 배웠습니다. 이번 글에서는 CSS 변수와 prefers-color-scheme 미디어 쿼리를 조합하여, OS 설정에 자동으로 반응하는 우아한 다크 모드 아키텍처 구현법을 상세히 알아보겠습니다.
1. 기초 공사: 컬러 팔레트를 변수로 캡슐화하라
다크 모드를 구현하기 위한 첫 단추는 하드코딩된 색상을 전부 금지하고, 모든 색상을 :root의 변수로 빼내는(추출) 작업입니다.
/* 1. 라이트 모드(기본) 컬러 팔레트 세팅 */
:root {
--bg-color: #ffffff; /* 배경은 하얀색 */
--text-color: #333333; /* 글씨는 어두운 회색 */
--border-color: #eeeeee; /* 연한 테두리 */
}
/* 2. 실제 요소에는 절대 직접 색상을 쓰지 않고 변수만 바인딩합니다! */
body {
background-color: var(--bg-color);
color: var(--text-color);
}
.card {
border: 1px solid var(--border-color);
}
이렇게 뼈대를 잡아두면 body나 .card의 코드는 영원히 수정할 필요가 없습니다. 오직 :root 안의 물감통 색깔만 바꿔치기하면 전체 사이트가 한 번에 옷을 갈아입기 때문입니다.
2. 브라우저가 다 알아서 해주는 마법: prefers-color-scheme
사용자의 윈도우나 맥(Mac), 아이폰 설정이 '다크 모드'로 되어 있는지 브라우저는 훔쳐볼 수 있습니다. 이를 감지하는 특수한 미디어 쿼리가 바로 @media (prefers-color-scheme: dark)입니다.
/* 사용자의 기기 설정이 '다크 모드'일 때만 아래 코드가 발동합니다! */
@media (prefers-color-scheme: dark) {
:root {
/* 물감통의 내용물만 어두운 테마로 싹 갈아엎어 버립니다! */
--bg-color: #121212; /* 배경은 짙은 검정 */
--text-color: #f5f5f5; /* 글씨는 하얀색 */
--border-color: #333333; /* 테두리도 어둡게 */
}
}
놀랍지 않나요? 이 미디어 쿼리 묶음 하나만 뚝딱 추가하면 사용자의 아이폰 화면이 다크 모드로 변하는 순간, 사이트 전체가 새로고침 없이 부드럽게 블랙 에디션으로 변신합니다!
3. 💡 실무형 끝판왕: 토글 버튼으로 다크 모드 수동 제어하기
OS 설정과 무관하게 사용자가 웹사이트 상단의 달(🌙) 모양 버튼을 눌러서 강제로 다크 모드를 켜고 끌 수 있게 만드는 것이 실무의 정석입니다. 이때는 미디어 쿼리 대신 HTML 속성(Attribute)과 자바스크립트를 조합합니다.
CSS: data-theme 속성을 기준으로 변수 세팅
/* body에 data-theme="dark"라는 꼬리표가 붙었을 때만 변수를 다크로 덮어씌움! */
body[data-theme="dark"] {
--bg-color: #121212;
--text-color: #f5f5f5;
/* ... 생략 ... */
}
JavaScript: 버튼 클릭 시 속성 뗐다 붙이기
const toggleBtn = document.querySelector('.dark-mode-btn');
toggleBtn.addEventListener('click', () => {
const currentTheme = document.body.getAttribute('data-theme');
// 다크면 지우고(라이트로 복귀), 아니면 다크를 붙여라!
if (currentTheme === 'dark') {
document.body.removeAttribute('data-theme');
} else {
document.body.setAttribute('data-theme', 'dark');
}
});
정리하며
다크 모드는 단순히 색상을 뒤집는 기술이 아닙니다. 진정한 어둠을 표현할 때는 완전한 검은색(#000000)을 피하고 짙은 쥐색(#121212)을 써서 눈부심을 막는 등 깊은 디자인 철학이 반영되어야 합니다. 이 엄청난 변수 기반 아키텍처를 세우고 나면, 여러분의 코드는 이제 수천 줄이 넘어가기 시작할 것입니다. 그 수천 줄의 코드가 충돌하고 꼬이는 것을 막기 위해서는 '이름을 짓는 강력한 규칙'이 필요합니다. 다음이번 포스팅에서는 전 세계 실무 프론트엔드 팀의 표준 작명소, "BEM 방법론과 유지보수하기 좋은 CSS 작성법"에 대해 뼈 때리게 파헤쳐 보겠습니다!
'StyleSheet > CSS' 카테고리의 다른 글
| [CSS] CSS 변수(Variables)와 테마 관리 (0) | 2026.08.10 |
|---|---|
| [CSS] CSS 애니메이션 완벽 가이드 (Transform, Transition, Keyframes) (0) | 2026.08.10 |
| [CSS] 반응형 웹디자인 (미디어 쿼리, 컨테이너 쿼리) (0) | 2026.08.10 |
| [CSS] Grid Layout - 2차원 레이아웃 마스터 클래스 (1) | 2026.08.10 |
| [CSS] Flexbox: 1차원 레이아웃의 모든 것 (0) | 2026.08.10 |