바텀 시트 디자인 시스템
목적
바텀 시트 디자인 시스템은 웹 인터페이스 및 프로그레시브 웹 애플리케이션(PWA)에서 슬라이드업 바텀 시트, 액션 시트, 모달 하단 서랍을 위한 표준화된 모바일 우선 디자인 프레임워크를 제공합니다. 큰 화면 비율의 현대 모바일 기기에서는 상단에 위치한 오버레이나 중앙 모달 팝업을 한 손으로 조작하기 어렵습니다. 바텀 시트는 인터랙티브 작업, 컨텍스트 메뉴, 필터 컨트롤, 상세 하위 뷰를 사용자의 엄지손가락이 자연스럽게 닿는 화면 하단에 고정합니다.
효과적인 바텀 시트 시스템을 설계하려면 디텐트 스냅 높이(피크/접힘, 부분/절반 높이, 전체 높이), 터치 드래그 어포던스(그립 핸들), 배경 디밍(스크림/배경), 바디 스크롤 잠금 메커니즘, 뷰포트 세이프 에어리어 인셋(env(safe-area-inset-bottom)), 그리고 넓은 뷰포트에서 바텀 시트를 중앙 모달이나 팝오버로 변환하는 원활한 반응형 데스크탑 변환이 필요합니다.
사용 사례
- 모바일 상품 옵션 선택기: PDP(상품 상세 페이지)에서 벗어나지 않고 크기, 색상, 수량, 구독 주기 선택기를 제공합니다.
- 모바일 필터 및 정렬 컨트롤: 전자상거래 카탈로그 페이지나 SaaS 검색 뷰에 대한 다중 필터 옵션을 제공하고 하단에 고정된 "필터 적용" 액션 바를 표시합니다.
- 컨텍스추얼 액션 시트: 소셜 피드, 미디어 카드, 데이터 테이블에서 원터치 빠른 작업(공유, 북마크, 목록에 추가, 신고)을 트리거합니다.
- 위치 및 지도 상세 카드: 지도 뷰 위로 슬라이드업되는 확장 가능한 관심 지점 세부 정보나 배송 추적 타임라인(피크 디텐트에서 전체 높이 확장)을 표시합니다.
- 모바일 다단계 하위 워크플로우: 체결 결제 수단 선택, 주소 선택, 빠른 피드백 제출과 같은 신속한 인라인 작업을 완료합니다.
사용하지 말아야 할 경우
- 전역 내비게이션 라우팅: 주요 앱 섹션 간의 기본 탐색에는
bottom-navigation-system또는site-navigation-system을 사용하세요. - 파괴적 확인 알림: 중요한 되돌릴 수 없는 작업(예: "계정 삭제")의 경우, 명시적 확인을 요구하는 중앙
overlay-and-dialog-system모달 다이얼로그(role="alertdialog")를 사용하세요. - 페이지 내 접을 수 있는 콘텐츠: 페이지 흐름 내에서 확장 가능한 콘텐츠를 토글하는 경우
accordion-ui-system또는tab-ui-system을 사용하세요. - 와이드스크린 데스크탑 레이아웃(1024px 초과): 데스크탑 화면에서 전체 너비 바텀 시트를 표시하지 마세요. UI를 중앙 모달 다이얼로그(
overlay-and-dialog-system), 사이드 서랍(dashboard-layout-system), 또는 고정 팝오버(tooltip-and-hint-system)로 변환하세요.
입력
- 작업 유형 및 깊이: 콘텐츠의 성격(빠른 원터치 액션 목록, 다중 필드 양식, 스크롤 가능한 상세 목록).
- 디텐트 설정: 스냅 높이 선택(단일 디텐트: 100% 전체 높이; 이중 디텐트: 50% 절반 및 100% 전체; 삼중 디텐트: 20% 피크, 50% 절반, 90% 전체).
- 트리거 컨텍스트: 시트를 시작하는 요소 또는 사용자 동작(버튼 탭, 길게 누르기, 스와이프 제스처, 딥 링크).
- 디자인 토큰: 표면 배경색, 테두리 반경, 드래그 핸들 크기, 고도 그림자, 배경 불투명도, 타이포그래피 스케일.
- 데스크탑 변환 전략: 1024px 이상 뷰포트에 대해 선택한 레이아웃 전환(중앙 모달로 변환, 고정 팝오버로 변환, 슬라이드인 사이드 서랍으로 변환).
출력
- 바텀 시트 해부학 사양: 드래그 핸들 바, 헤더(제목 + 닫기 버튼), 스크롤 가능한 본문, 고정 푸터(CTA 바), 세이프 에어리어 인셋 패딩을 정의하는 레이아웃 청사진.
- 디텐트 높이 및 제스처 토큰 행렬: CSS 변수 및 스냅 임계값 정의(
--sheet-detent-peek,--sheet-detent-half,--sheet-detent-full)와 드래그 속도 해제 규칙. - 배경 및 고도 사양: 배경 불투명도 토큰, 배경 블러 필터 설정, z-index 계층 구조, 바디 스크롤 잠금 규칙(
overflow: hiddenon body). - 키보드 및 스크린 리더 ARIA 매핑:
role="dialog",aria-modal="true",aria-labelledby, 포커스 트랩 사양,Escape키 핸들러 정의. - 반응형 데스크탑 변환 청사진: 모바일 바텀 시트를 태블릿 및 데스크탑용 중앙 모달 다이얼로그 또는 팝오버로 변환하는 미디어 쿼리 중단점.
워크플로우
1. 시트 유형 및 디텐트 구조 분류
콘텐츠 양과 상호작용 빈도에 따라 적절한 디텐트 모드를 선택합니다:
- 비모달 액션 시트(피크/콘텐츠 맞춤): 짧은 콘텐츠(2–5개의 메뉴 액션)에 맞게 자동 크기 조정됩니다. 높이는 일반적으로 180px에서 320px 사이입니다. 액션 선택 또는 배경 탭 시 해제됩니다.
- 절반 높이/이중 디텐트 시트(50% 및 90% 뷰포트): 상품 변형 선택이나 정렬과 같은 중간 밀도 작업에 사용됩니다. 50% 높이(
50vh)로 열리고 위로 드래그하면 90% 높이(90vh)로 스냅됩니다. - 전체 높이/확장 시트(90%–100% 뷰포트): 다중 필터나 체크아웃 단계와 같은 복잡한 모바일 워크플로우에 사용됩니다. 고정된 헤더와 푸터, 내부 스크롤 가능 본문을 제공합니다.
2. 시각적 해부학 및 공간 계층 정의
5개의 별도 해부학적 레이어를 사용하여 시트를 구성합니다:
- 배경(스크림): 전체 뷰포트를 덮는 고정 오버레이(
background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px); z-index: 1000;). - 시트 컨테이너: 하단 화면 가장자리에 고정된 패널(
position: fixed; bottom: 0; left: 0; right: 0; border-radius: 16px 16px 0 0; background: var(--surface-bg); z-index: 1001;). - 드래그 핸들 바(어포던스): 상단 중앙의 시각적 알약(
width: 36px; height: 5px; border-radius: 999px; background: var(--border-neutral); margin: 8px auto; cursor: grab;). - 헤더 레이어: 시트 제목(
h2), 선택적 부제목, 명시적 닫기 버튼(<button aria-label="시트 닫기">✕</button>)을 포함합니다. - 스크롤 가능한 본문 레이어:
overflow-y: auto; -webkit-overflow-scrolling: touch;로 구성된 내부 콘텐츠 컨테이너. - 고정 푸터 CTA 레이어: 기본/보조 버튼과 세이프 에어리어 인셋 패딩이 있는 하단 고정 액션 바(
padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px))).
3. 제스처, 스냅 및 해제 메커니즘 설정
물리적 제스처 피드백을 위한 부드러운 터치 상호작용을 설정합니다:
- 드래그 어포던스 상호작용: 드래그 핸들이나 헤더를 아래로 드래그하면 시트가
transform: translateY()를 사용하여 부드럽게 아래로 이동합니다. - 스냅 임계값:
- 현재 높이의 30% 이상 드래그하거나 속도 0.5px/ms 초과로 아래로 플릭하면 전체 닫힘을 트리거합니다.
- 이중 디텐트 모드에서 30%와 70% 사이로 드래그하면 가장 가까운 디텐트(50% 또는 90%)로 스냅됩니다.
- 스크롤 잠금 충돌: 스크롤 가능한 본문 레이어 내부에서 드래그할 때, 본문 스크롤 위치가
scrollTop === 0이고 사용자가 아래로 스와이프하는 경우에만 시트 드래그-해제를 시작합니다. - 바디 스크롤 잠금: 모달 바텀 시트가 열려 있을 때
document.body에overflow: hidden을 적용하여 배경 페이지 스크롤 누출을 방지합니다.
4. 뷰포트 세이프 에어리어 및 표면 대비 구현
모바일 하드웨어 디스플레이 컷아웃 및 라이트/다크 모드와의 완전한 시각적 통합을 보장합니다:
- 세이프 에어리어 인셋 처리: 시트 컨테이너 또는 고정 푸터에 항상
padding-bottom: env(safe-area-inset-bottom, 16px)을 적용하여 콘텐츠/버튼이 iOS 홈 표시줄에 가려지지 않도록 합니다. - 최대 높이 제한: 전체 높이 시트의 최대 높이를
max-height: calc(100vh - 48px)또는max-height: calc(100dvh - 48px)로 제한하여 상단에 흐릿한 상위 페이지 컨텍스트의 48px 조각이 보이도록 합니다. - 표면 고도: 깊은 고도 그림자 토큰(
box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.15))을 사용하여 배경 페이지 콘텐츠와의 분리를 만듭니다.
5. 접근성 및 키보드 내비게이션 구성
WCAG 2.1 / 2.2 AA 표준을 완전히 준수합니다:
- ARIA 역할: 컨테이너는
role="dialog"또는role="region"(비모달 피킹 시트의 경우),aria-modal="true",aria-labelledby="sheet-title-id"를 사용해야 합니다. - 포커스 관리:
- 열리면 첫 번째 포커스 가능한 요소(시트 내부) 또는 닫기 버튼으로 프로그래밍 방식으로 포커스를 이동합니다.
Tab또는Shift+Tab이 시트에서 비활성 배경으로 빠져나가는 것을 방지하는 포커스 트랩을 구현합니다.- 닫히면 시트를 연 트리거 요소로 포커스를 복원합니다.
- 키보드 컨트롤:
Escape키를 누르면 즉시 시트가 닫혀야 합니다. - 스크린 리더 알림: 시트 내부의 동적 콘텐츠 변경은
aria-live="polite"영역을 사용해야 합니다.
6. 반응형 데스크탑 변환 설계
데스크탑 모니터(1024px 이상)에서 전체 너비로 늘어나면 바텀 시트가 보기 흉해집니다. 명시적인 반응형 변환 규칙을 구현합니다:
- 데스크탑 모달 모드(기본값): 1024px 이상 뷰포트에서 바텀 시트를 중앙 모달 다이얼로그로 전환합니다(
width: 100%; max-width: 540px; border-radius: 16px; margin: auto; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);). - 데스크탑 팝오버 모드(컨텍스트 메뉴): 빠른 액션 시트의 경우 트리거 버튼 옆에 위치한 고정 팝오버로 전환합니다.
- 데스크탑 사이드 서랍 모드(복잡한 양식/필터): 다중 필터 또는 다단계 흐름의 경우 오른쪽 정렬 슬라이드인 사이드 서랍으로 전환합니다(
width: 400px; height: 100vh; top: 0; right: 0; border-radius: 16px 0 0 16px;).
결정 규칙
디텐트 선택 행렬
| 시트 유형 | 디텐트 설정 | 콘텐츠 양 | 이상적인 사용 사례 |
|---|---|---|---|
| 액션 시트 | 콘텐츠 맞춤(단일 디텐트) | 2–6개의 액션 링크/항목 | 빠른 공유, 컨텍스트 메뉴, 간단한 옵션 전환. |
| 선택 시트 | 이중 디텐트(50vh 초기, 90vh 확장) | 5–15개의 스크롤 가능 항목 | 상품 크기/색상 선택기, 주소 선택기, 결제 수단. |
| 인터랙티브 서랍 | 삼중 디텐트(120px 피크, 50vh, 90vh) | 복잡한 공간/지도 데이터 | 배송 추적 지도 카드, 실시간 교통 정류장, 라이드셰어 상세 정보. |
| 전체 흐름 시트 | 단일 디텐트(90vh - 100vh 고정) | 다중 섹션 양식/필터 | 카탈로그 다중 필터, 모바일 체크아웃 단계, 설문 워크플로우. |
데스크탑 변환 선택
- 중앙 모달 사용: 시트에 구조화된 양식, 변형 선택기, 또는 체크아웃 옵션이 포함된 경우.
- 고정 팝오버 사용: 시트에 짧은 컨텍스트 작업(공유, 편집, 삭제)이 포함된 경우.
- 사이드 서랍 사용: 시트에 대시보드 및 데이터 테이블의 필터 컨트롤 또는 편집 패널이 포함된 경우.
제약 조건
- 접근성(WCAG 2.1 / 2.2 AA):
aria-modal="true"가 활성화된 경우 명시적인 포커스 트래핑을 제공해야 합니다.- 모든 내부 항목 및 닫기 버튼의 터치 대상은 최소 44x44px여야 합니다(WCAG 2.5.8 / 2.5.5).
- 모달 바텀 시트 뒤의 배경 콘텐츠는
inert로 표시하거나 보조 기술에서 숨겨야 합니다.
- 터치 및 제스처 크기:
- 드래그 핸들의 히트 대상은 시각적 핸들이 36x5px이더라도 보이지 않는 패딩으로 확장되어야 합니다(
min-height: 24px,min-width: 60px).
- 드래그 핸들의 히트 대상은 시각적 핸들이 36x5px이더라도 보이지 않는 패딩으로 확장되어야 합니다(
- 뷰포트 동적 단위:
- 지원되는 경우
dvh(동적 뷰포트 높이)를 사용하고(height: 90dvh), 지원되지 않는 경우vh로 대체하여 동적 모바일 주소 표시줄 확장 및 축소를 수용합니다.
- 지원되는 경우
일반적인 실패 패턴
- 누락된 세이프 에어리어 패딩:
env(safe-area-inset-bottom)을 생략하여 하단 푸터 액션 버튼이 iOS 제스처 바와 겹치는 경우. - 데스크탑에서 전체 너비로 늘어난 시트: 모바일 바텀 시트가 데스크탑 모니터에서 1920px 너비로 확장되는 경우.
- 스크롤 하이재킹 잠금: 콘텐츠 스크롤과 시트 드래그-해제 제스처를 분리하지 못하여 사용자가 텍스트를 아래로 스크롤하려고 할 때 시트가 접히는 경우.
- 키보드 Escape 핸들러 누락:
Escape키 이벤트 리스너를 생략하여 데스크탑 키보드 사용자를 모달 시트 오버레이에 가두는 경우. - 배경으로 포커스 누출: 모달 바텀 시트가 열려 있는 동안
Tab키를 통해 배경 페이지 요소에 도달할 수 있는 경우.
검증 기준
- 시트 레이아웃에 명시적인 시각적 드래그 어포던스, 제목이 있는 헤더, 스크롤 가능한 본문, 고정 푸터가 포함됩니다.
- 고정 푸터 및 시트 컨테이너에 세이프 에어리어 인셋(
padding-bottom: env(safe-area-inset-bottom))이 구현됩니다. - 드래그 핸들 히트 영역이 터치 접근성을 위한 최소 44px 높이를 충족합니다.
- 시트가
role="dialog",aria-modal="true",aria-labelledby를 사용하고 활성화된 동안 포커스를 트랩합니다. -
Escape키를 누르거나 배경을 탭하면 모달 시트가 닫히고 트리거 버튼으로 포커스가 복원됩니다. - 모달 시트가 열려 있는 동안 배경 본문 스크롤이 잠깁니다(
overflow: hidden). - 1024px 이상 뷰포트에서 바텀 시트를 중앙 모달 다이얼로그, 팝오버 또는 사이드 서랍으로 깔끔하게 변환합니다.