- 사이드바 메뉴 3depth 이상 지원 (재귀 컴포넌트) - menuTransform.ts: buildChildrenRecursive 함수 추가 - AuthenticatedLayout.tsx: findMenuRecursive + ancestorIds 배열로 경로 매칭 - Sidebar.tsx: depth별 스타일 (1depth: 아이콘+굵은텍스트, 2depth: 작은아이콘, 3depth: dot+작은텍스트) - CEO 대시보드 상세 모달 및 카드 관리 개선 - 폴더블 기기 레이아웃 가이드 문서 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
154 lines
4.6 KiB
Markdown
154 lines
4.6 KiB
Markdown
# 폴더블 기기(Galaxy Fold) 레이아웃 대응 가이드
|
|
|
|
> 작성일: 2026-01-09
|
|
> 적용 파일: `AuthenticatedLayout.tsx`, `globals.css`
|
|
|
|
---
|
|
|
|
## 문제 현상
|
|
|
|
Galaxy Fold 같은 폴더블 기기에서 **넓은 화면 ↔ 좁은 화면** 전환 시:
|
|
- 사이트 너비가 정확히 계산되지 않음
|
|
- 전체 레이아웃이 틀어짐
|
|
- 화면 전환 후에도 이전 크기가 유지됨
|
|
|
|
---
|
|
|
|
## 원인 분석
|
|
|
|
### 1. `window.innerWidth`의 한계
|
|
```javascript
|
|
// 기존 코드
|
|
window.addEventListener('resize', () => {
|
|
setIsMobile(window.innerWidth < 768);
|
|
});
|
|
```
|
|
- 폴더블 기기에서 화면 전환 시 `window.innerWidth` 값이 **즉시 업데이트되지 않음**
|
|
- `resize` 이벤트가 불완전하게 발생
|
|
|
|
### 2. CSS `100vh` / `100vw` 문제
|
|
```css
|
|
/* 기존 */
|
|
height: 100vh; /* h-screen */
|
|
```
|
|
- Tailwind의 `h-screen`은 `100vh`로 계산됨
|
|
- 폴더블 기기에서 viewport units가 **늦게 재계산**되어 레이아웃 깨짐
|
|
|
|
---
|
|
|
|
## 해결 방법
|
|
|
|
### 1. visualViewport API 사용
|
|
|
|
`window.visualViewport`는 실제 보이는 viewport 크기를 더 정확하게 반환합니다.
|
|
|
|
```typescript
|
|
// src/layouts/AuthenticatedLayout.tsx
|
|
|
|
useEffect(() => {
|
|
const updateViewport = () => {
|
|
// visualViewport API 우선 사용 (폴더블 기기에서 더 정확)
|
|
const width = window.visualViewport?.width ?? window.innerWidth;
|
|
const height = window.visualViewport?.height ?? window.innerHeight;
|
|
|
|
setIsMobile(width < 768);
|
|
|
|
// CSS 변수로 실제 viewport 크기 설정
|
|
document.documentElement.style.setProperty('--app-width', `${width}px`);
|
|
document.documentElement.style.setProperty('--app-height', `${height}px`);
|
|
};
|
|
|
|
updateViewport();
|
|
|
|
// resize 이벤트
|
|
window.addEventListener('resize', updateViewport);
|
|
|
|
// visualViewport resize 이벤트 (폴드 전환 감지)
|
|
window.visualViewport?.addEventListener('resize', updateViewport);
|
|
|
|
return () => {
|
|
window.removeEventListener('resize', updateViewport);
|
|
window.visualViewport?.removeEventListener('resize', updateViewport);
|
|
};
|
|
}, []);
|
|
```
|
|
|
|
### 2. CSS 변수 + dvw/dvh fallback
|
|
|
|
```css
|
|
/* src/app/[locale]/globals.css */
|
|
|
|
:root {
|
|
/* 폴더블 기기 대응 - JS에서 동적으로 업데이트됨 */
|
|
--app-width: 100vw;
|
|
--app-height: 100vh;
|
|
|
|
/* dvh/dvw fallback (브라우저 지원 시 자동 적용) */
|
|
--app-height: 100dvh;
|
|
--app-width: 100dvw;
|
|
}
|
|
```
|
|
|
|
| 단위 | 설명 |
|
|
|------|------|
|
|
| `vh/vw` | 초기 viewport 기준 (고정) |
|
|
| `dvh/dvw` | Dynamic viewport - 동적으로 변함 |
|
|
| `svh/svw` | Small viewport - 최소 크기 기준 |
|
|
| `lvh/lvw` | Large viewport - 최대 크기 기준 |
|
|
|
|
### 3. 레이아웃에서 CSS 변수 사용
|
|
|
|
```tsx
|
|
// 기존: h-screen (100vh 고정)
|
|
<div className="h-screen flex flex-col">
|
|
|
|
// 변경: CSS 변수 사용 (동적 업데이트)
|
|
<div className="flex flex-col" style={{ height: 'var(--app-height)' }}>
|
|
```
|
|
|
|
---
|
|
|
|
## 작동 원리
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────┐
|
|
│ 폴드 전환 발생 │
|
|
│ ↓ │
|
|
│ visualViewport resize 이벤트 발생 │
|
|
│ ↓ │
|
|
│ updateViewport() 실행 │
|
|
│ ↓ │
|
|
│ CSS 변수 업데이트 (--app-width, --app-height) │
|
|
│ ↓ │
|
|
│ 레이아웃 즉시 재계산 │
|
|
└─────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 브라우저 지원
|
|
|
|
| API/속성 | Chrome | Safari | Firefox | Samsung Internet |
|
|
|----------|--------|--------|---------|------------------|
|
|
| `visualViewport` | 61+ | 13+ | 91+ | 8.0+ |
|
|
| `dvh/dvw` | 108+ | 15.4+ | 101+ | 21+ |
|
|
|
|
- `visualViewport` 미지원 시 → `window.innerWidth/Height` fallback
|
|
- `dvh/dvw` 미지원 시 → JS에서 계산한 값으로 대체
|
|
|
|
---
|
|
|
|
## 관련 파일
|
|
|
|
| 파일 | 역할 |
|
|
|------|------|
|
|
| `src/layouts/AuthenticatedLayout.tsx` | viewport 감지 및 CSS 변수 업데이트 |
|
|
| `src/app/[locale]/globals.css` | CSS 변수 선언 및 fallback |
|
|
|
|
---
|
|
|
|
## 참고 자료
|
|
|
|
- [MDN - Visual Viewport API](https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API)
|
|
- [MDN - Viewport Units](https://developer.mozilla.org/en-US/docs/Web/CSS/length#viewport-percentage_lengths)
|
|
- [web.dev - New Viewport Units](https://web.dev/viewport-units/) |