# 폴더블 기기(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 고정)
// 변경: CSS 변수 사용 (동적 업데이트)
``` --- ## 작동 원리 ``` ┌─────────────────────────────────────────────────────┐ │ 폴드 전환 발생 │ │ ↓ │ │ 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/)