SpinFlow 블로그 · 2026-09-17

CSS 그림자는 기본·호버·포커스 상태를 함께 설계하세요

그림자 코드를 상태별로 나누고 접근성을 해치지 않게 검토하는 방법입니다.

글 요약

그림자 코드를 상태별로 나누고 접근성을 해치지 않게 검토하는 방법입니다. 본문은 브라우저에서 전체 내용과 함께 표시됩니다.

CSS 그림자는 장식처럼 보이지만 컴포넌트 상태를 구분하는 시각적 신호가 될 수 있습니다. 기본 상태와 호버 상태가 같은 그림자를 쓰면 마우스가 올라갔는지 알기 어렵고, 키보드 포커스를 그림자 하나로만 표시하면 고대비 환경에서 신호가 사라질 수 있습니다. 따라서 그림자 값을 먼저 만들기보다 상태와 사용자의 행동을 먼저 표로 정하는 편이 좋습니다.

SpinFlow의 CSS Box Shadow 생성기는 오프셋, 흐림, 퍼짐, 불투명도, 색상, inset 여부를 조정해 하나의 `box-shadow` 선언을 미리 보여 줍니다. 상태별 규칙을 자동으로 설계하는 도구는 아니므로, 생성 결과를 기본·호버·포커스에 각각 어떻게 적용할지는 직접 결정해야 합니다. 이 글에서는 상태를 작은 상태 머신처럼 나누고, 복사한 코드를 접근성 검수까지 연결합니다.

기본·호버·포커스·비활성 상태를 표로 정의하기

먼저 요소가 어떤 상태를 가질 수 있는지 적습니다. 버튼이라면 기본, 마우스 호버, 키보드 포커스, 눌림, 비활성 상태가 있을 수 있습니다. 카드라면 기본과 호버만 필요할 수도 있고, 링크가 있다면 포커스 표시를 별도로 추가해야 합니다. 모든 요소에 같은 그림자를 복사하는 대신 상태별 목적을 한 줄로 설명하세요.

상태사용자에게 전달할 신호검토 질문
기본요소가 화면에 놓여 있음배경과 구분되는가?
호버마우스가 대상 위에 있음움직임이 과하지 않은가?
포커스키보드 입력 대상임그림자 외 신호도 있는가?
비활성현재 실행할 수 없음읽을 수 있는 상태인가?

호버와 포커스는 같은 상태가 아닙니다. 마우스를 쓰지 않는 사용자는 호버를 경험하지 않지만 포커스는 반드시 확인할 수 있어야 합니다. 포커스 스타일을 호버에만 넣거나, 호버 그림자를 포커스의 유일한 신호로 쓰면 키보드 사용자가 현재 위치를 잃을 수 있습니다.

box-shadow의 offset·blur·spread·alpha 해부하기

CSS 그림자 생성기의 결과는 대체로 `box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.5);`처럼 표시됩니다. 첫 번째 값은 수평 오프셋, 두 번째는 수직 오프셋, 세 번째는 흐림 반경, 네 번째는 퍼짐 반경, 마지막은 색상과 불투명도입니다. `inset`을 켜면 그림자가 요소 바깥이 아니라 안쪽에 생깁니다.

수평 오프셋을 양수로 바꾸면 그림자가 오른쪽으로, 음수로 바꾸면 왼쪽으로 이동합니다. 수직 오프셋은 아래·위 방향을 정하고, blur가 커질수록 경계가 부드러워집니다. spread는 그림자 영역을 넓히거나 줄이는 값입니다. 같은 색상이라도 이 네 값의 조합이 달라지면 요소가 떠 있는지 눌려 있는지에 대한 인상이 크게 달라집니다.

불투명도는 0부터 1 사이에서 0.01 단위로 조정할 수 있습니다. 0이면 그림자가 거의 보이지 않고, 1이면 색상이 완전히 불투명하게 나타납니다. 검정색에 높은 불투명도와 큰 spread를 함께 쓰면 화면이 무거워질 수 있으므로, 미리보기와 실제 배경을 함께 봐야 합니다.

그림자 값은 색상 선택과도 연결됩니다. HEX 입력이 올바른 6자리 색상이 아니면 변환 함수가 검정 계열 기본값으로 처리할 수 있으므로, 색상 코드를 직접 타이핑한 뒤에는 미리보기와 생성된 rgba 값을 확인하세요. 값이 기대와 다르면 복사하기 전에 입력을 수정합니다.

생성기의 슬라이더 범위와 기본값 이해하기

수평·수직 오프셋은 -50px부터 50px, blur는 0px부터 100px, spread는 -50px부터 50px 범위에서 움직입니다. 불투명도는 0부터 1까지 0.01 단위로 조절합니다. 이 범위는 빠른 시각 조정에 충분하지만, 모든 디자인 시스템의 허용 범위를 뜻하지는 않습니다. 프로젝트에서 8px 간격이나 특정 토큰을 사용한다면 생성 후 값을 토큰에 맞게 다듬어야 합니다.

기본값은 수평 0, 수직 4, blur 10, spread 0, 불투명도 0.5, 검정색, 바깥 그림자입니다. 이 값을 출발점으로 사용하되 ‘기본값이라서 적절하다’고 생각하지 마세요. 흰 카드 위에서 어두운 그림자는 잘 보이지만, 어두운 배경이나 저대비 화면에서는 의도와 다르게 보일 수 있습니다.

초기화 버튼은 현재 생성기의 값을 기본 상태로 되돌리는 기능입니다. 팀에서 여러 시안을 비교할 때는 초기화 후 한 변수만 바꾸는 방식이 좋습니다. 예를 들어 blur를 먼저 고정한 뒤 spread만 조절하면 어떤 값이 카드의 부피감에 영향을 주었는지 설명할 수 있습니다.

슬라이더가 만드는 숫자를 최종 디자인 토큰에 바로 저장하기보다, 요소·상태·배경·검토 화면을 함께 기록하세요. 같은 `0 4px 10px`도 카드 크기와 주변 색상에 따라 다르게 느껴집니다. 코드보다 사용 맥락이 먼저 정해져야 합니다.

호버와 focus-visible을 다른 신호로 설계하기

호버에서는 작은 이동감이나 부드러운 그림자 변화를 줄 수 있습니다. 예를 들어 기본 상태를 `0 4px 10px 0 rgba(0, 0, 0, 0.24)`로 두고 호버에서 `0 6px 16px 0 rgba(0, 0, 0, 0.20)`처럼 바꾸면 요소가 조금 떠오르는 인상을 만들 수 있습니다. 이 값은 예시일 뿐이며, 실제 배경과 카드 크기에 맞춰 검토해야 합니다.

포커스는 그림자의 범위를 바깥으로 넓혀 대상의 경계를 분명히 하는 방식이 흔합니다. 예를 들어 `0 0 0 3px rgba(14, 165, 233, 0.85)`와 같은 ring 형태를 별도 규칙으로 둘 수 있습니다. 그러나 포커스 링의 색상과 두께는 배경, 버튼 색, 주변 요소와 함께 확인해야 하며, 호버 상태에서만 나타나게 만들면 안 됩니다.

CSS에서는 마우스 호버와 키보드 포커스를 보통 각각 `:hover`, `:focus-visible`로 구분합니다. 도구는 하나의 그림자 선언을 만들 뿐 이 선택자를 자동으로 붙이지 않습니다. 생성 결과를 복사한 뒤 실제 컴포넌트의 선택자에 넣고, Tab 키로 이동하면서 포커스가 항상 보이는지 테스트하세요.

눌림 상태에서는 그림자를 줄이거나 inset으로 바꿀 수 있지만, 애니메이션과 함께 쓰면 움직임이 과해질 수 있습니다. 이 생성기는 그림자의 숫자와 미리보기만 조정하므로 transition 지속 시간이나 모션 감소 설정은 별도 CSS에서 검토해야 합니다. 상태 변화가 빠르게 반복될 때 눈의 피로가 생기지 않는지도 확인하세요.

키보드 포커스와 고대비 환경에서 확인하기

포커스 검수는 마우스를 사용하지 않고 Tab 키만으로 시작합니다. 현재 대상이 어디인지, 다음 대상이 어디인지, 포커스가 배경과 버튼 색상에 묻히지 않는지 확인하세요. 그림자가 희미해도 테두리나 outline 같은 추가 신호가 있으면 위치를 파악하기 쉬워집니다. 포커스가 보이지만 클릭 상태와 구분되지 않는 경우도 수정 대상입니다.

고대비 모드나 강제 색상 환경에서는 box-shadow가 제거되거나 다른 색으로 덮일 수 있습니다. 그림자만으로 포커스를 표시하면 이런 환경에서 대상이 사라질 수 있으므로, outline·border·배경 변화처럼 다른 표현을 함께 준비하세요. 색상 대비 검사는 그림자 생성기에서 제공하지 않으므로 별도의 접근성 검수 절차가 필요합니다.

비활성 상태는 단순히 그림자를 없애는 것으로 끝내지 않습니다. 버튼이 실행되지 않는다는 사실을 텍스트와 상태 속성으로도 전달해야 하고, 너무 낮은 대비로 글자가 읽히지 않게 만들면 안 됩니다. 그림자는 깊이감을 조정하는 장식이고, 활성 가능 여부를 전달하는 유일한 의미 신호가 되어서는 안 됩니다.

실제 테스트 기록에는 브라우저, 키보드 사용 여부, 고대비 설정, 화면 배경, 포커스가 보였는지를 적습니다. ‘그림자가 예쁘다’는 주관적인 평가보다 ‘Tab 이동 시 3px ring이 카드 배경에서 구분됨’처럼 조건과 결과를 쓰면 수정 방향이 분명해집니다.

복사한 CSS를 실제 버튼과 카드에 적용하기

복사한 선언은 먼저 작은 실험용 컴포넌트에 붙입니다. 기본·호버·포커스·비활성 네 상태를 각각 만들고, 버튼의 텍스트가 짧을 때와 길 때를 모두 확인합니다. 카드라면 이미지가 있는 경우와 없는 경우, 제목이 한 줄과 두 줄인 경우를 비교하세요. 그림자 자체만 확인하면 주변 콘텐츠와의 충돌을 발견하기 어렵습니다.

색상 값을 조정할 때는 색상 코드 변환기에서 HEX·RGB·HSL 표기를 검산할 수 있습니다. 그림자 색을 바꾼 뒤에도 원본 색상과 불투명도를 기록하고, 입력이 잘못되어 검정으로 대체되지 않았는지 생성된 rgba 문자열을 확인하세요.

생성기의 결과를 CSS 파일에 넣은 뒤에는 같은 선언이 여러 컴포넌트에 중복되지 않는지 살펴봅니다. 디자인 토큰이나 공통 클래스가 있다면 한 곳에서 관리하고, 예외 상태만 개별 컴포넌트에 둡니다. 같은 값을 여러 파일에 복사하면 나중에 그림자 정책을 바꿀 때 일부 화면이 남을 수 있습니다.

문서나 코드 예시로 공유할 때는 Markdown 미리보기에서 코드 블록과 설명이 제대로 보이는지 확인하세요. CSS 한 줄만 공유하면 `inset` 여부, 상태 선택자, 적용 대상이 생략되어 다른 사람이 잘못 사용할 수 있습니다. 값뿐 아니라 상태와 적용 범위를 함께 적습니다.

여러 그림자와 상태별 예외를 수동으로 확장하기

CSS `box-shadow`는 쉼표로 여러 그림자를 연결할 수 있지만, 현재 생성기 화면은 하나의 그림자 값을 만들도록 설계되어 있습니다. 외곽 그림자와 포커스 ring을 동시에 쓰려면 생성 결과를 복사한 뒤 두 선언을 쉼표로 결합하고, 실제 브라우저에서 겹침과 색상 혼합을 확인해야 합니다. 자동으로 두 값을 조합해 준다고 생각하면 안 됩니다.

예를 들어 외곽 그림자와 포커스 ring을 함께 적용할 때는 각 값의 목적과 순서를 메모합니다. 첫 번째 값이 외곽 깊이, 두 번째 값이 포커스 표시라면 포커스가 배경에 묻히지 않는지 확인합니다. spread가 큰 값이 다른 요소와 겹치거나 스크롤 영역을 넓히는 경우도 있으므로 시각적 결과와 레이아웃 영향을 함께 살펴야 합니다.

상태별 예외가 많아지면 그림자 값만으로 해결하려 하지 마세요. 아이콘, 라벨, 테두리, 배경색을 조합해 상태 의미를 분산하면 한 가지 CSS 속성에 대한 의존도가 낮아집니다. 디자인 시스템 문서에는 기본값과 예외값, 적용 대상, 접근성 대체 신호를 함께 기록하는 것이 좋습니다.

최종 QA에서 확인할 항목

최종 검수에서는 첫째 기본 상태에서 요소와 배경이 구분되는지, 둘째 호버가 과도한 이동이나 깜빡임을 만들지 않는지, 셋째 Tab 키 포커스가 항상 보이는지, 넷째 고대비 환경에서 그림자 없이도 상태를 알 수 있는지 확인합니다. 다섯째 모바일 터치에서는 호버만을 전제로 한 설명이 남아 있지 않은지 봅니다.

그림자 값은 작아 보여도 여러 카드와 버튼에 반복되면 페이지 전체의 대비와 성능 인상에 영향을 줄 수 있습니다. 큰 blur와 spread를 여러 겹 쌓으면 시각적으로 무거워지고, 작은 화면에서 경계가 흐려질 수 있습니다. 필요한 상태에 필요한 만큼만 사용하고, 공통 토큰으로 관리해 일관성을 유지하세요.

CSS 그림자 생성기의 역할은 숫자를 시각적으로 조정하고 복사 가능한 한 줄을 만드는 데 있습니다. 상태 설계, 키보드 접근성, 고대비 대체 표시, 여러 그림자 조합은 구현자와 검토자가 완성해야 합니다. 상태 표를 먼저 만들고 도구 결과를 그 표에 맞춰 사용하면 장식과 기능 신호가 뒤섞이는 일을 줄일 수 있습니다.

관련 도구와 참고 자료