UI v0.20.1 모달고정헤더푸터및배경스크롤잠금 - #37
Hidden character warning
Conversation
config.title/footer로 상단·하단을 고정하고 가운데 본문만 스크롤되도록 Modal을 header/body/footer 3영역으로 재구성. body에 min-height:0+overflow-y 적용으로 스크롤 영역을 격리하고, role=dialog를 모달 박스로 이동하며 title에 aria-labelledby를 연결해 접근성을 보강. 기존 content-only 사용과 하위 호환 유지. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
모달·다이얼로그가 열려 있는 동안 body 스크롤을 잠그는 useScrollLock 훅 추가. 모듈단위 참조 카운팅으로 중첩 오버레이를 처리해 마지막 하나가 닫힐 때만 해제하고, 사라진 스크롤바 폭만큼 padding-right를 보정해 배경 밀림을 방지. Modal과 ConfirmDialog에 적용(Toast는 배경 조작 허용을 위해 제외). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Default 스토리의 제목·닫기 버튼을 title/footer 영역으로 이동해 정리하고, 긴 본문으로 고정 헤더/푸터 스크롤 동작을 보여주는 Sticky 예제를 추가. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs 사이트 modal.md에 title/footer API, 고정 헤더/푸터 사용법, 배경 스크롤 잠금, 접근성(aria-labelledby) 섹션과 API 표를 갱신. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Code Review
This pull request introduces background scroll locking for overlays (such as ConfirmDialog and Modal) using a new useScrollLock hook, and adds support for sticky headers and footers in the Modal component to allow only the body content to scroll. Review feedback suggests optimizing the modal's CSS padding to prevent double-padding issues when both header and footer are present, and replacing useEffect with a safe useLayoutEffect wrapper in useScrollLock to prevent layout flickering on mount.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| /* 상단 고정 영역 (스크롤되지 않음) */ | ||
| .yds-modal-header { | ||
| flex-shrink: 0; | ||
| padding: var(--yds-content-padding); | ||
| } | ||
|
|
||
| .yds-modal-title { | ||
| margin: 0; | ||
| } | ||
|
|
||
| /* 스크롤되는 본문 영역 */ | ||
| .yds-modal-body { | ||
| flex: 1 1 auto; | ||
| /* flex 자식이 넘칠 때 스크롤되도록 하는 필수 조건 */ | ||
| min-height: 0; | ||
| overflow-y: auto; | ||
| padding: var(--yds-content-padding); | ||
| } | ||
|
|
||
| /* 하단 고정 영역 (스크롤되지 않음) */ | ||
| .yds-modal-footer { | ||
| flex-shrink: 0; | ||
| padding: var(--yds-content-padding); | ||
| } |
There was a problem hiding this comment.
📐 모달 헤더/바디/푸터 여백 중첩 개선 (하위 호환성 유지)
현재 설정으로는 title과 footer가 모두 존재할 때, 각각 var(--yds-content-padding) 만큼의 패딩을 가지게 되어 영역 간의 간격이 너무 넓어지는 현상(더블 패딩)이 발생할 수 있습니다.
기존에 content만 단독으로 사용하던 경우의 하위 호환성(사방 패딩 유지)을 보장하면서, 헤더와 푸터가 추가되었을 때 영역 간의 간격을 자연스럽게 조절하기 위해 CSS 인접 형제 선택자(+)와 :not(:last-child) 가상 클래스를 활용하는 방식을 제안합니다.
/* 상단 고정 영역 (스크롤되지 않음) */
.yds-modal-header {
flex-shrink: 0;
padding: var(--yds-content-padding) var(--yds-content-padding) 0;
}
.yds-modal-title {
margin: 0;
}
/* 스크롤되는 본문 영역 */
.yds-modal-body {
flex: 1 1 auto;
/* flex 자식이 넘칠 때 스크롤되도록 하는 필수 조건 */
min-height: 0;
overflow-y: auto;
padding: var(--yds-content-padding);
}
/* 헤더가 있을 경우 본문 상단 패딩 조절 (여백 중첩 방지) */
.yds-modal-header + .yds-modal-body {
padding-top: calc(var(--yds-content-padding) / 2);
}
/* 푸터가 있을 경우 본문 하단 패딩 조절 (여백 중첩 방지) */
.yds-modal-body:not(:last-child) {
padding-bottom: calc(var(--yds-content-padding) / 2);
}
/* 하단 고정 영역 (스크롤되지 않음) */
.yds-modal-footer {
flex-shrink: 0;
padding: 0 var(--yds-content-padding) var(--yds-content-padding);
}| @@ -0,0 +1,44 @@ | |||
| import { useEffect } from 'react' | |||
There was a problem hiding this comment.
⚡ SSR 대응 및 레이아웃 흔들림 방지를 위한 useLayoutEffect 도입
useEffect는 브라우저가 화면을 그린(paint) 후에 비동기적으로 실행되므로, 모달이 열릴 때 아주 잠깐 스크롤바가 보였다가 사라지면서 레이아웃이 미세하게 흔들리는 현상(Flicker)이 발생할 수 있습니다.
화면을 그리기 전에 동기적으로 스크롤을 잠그기 위해 useLayoutEffect를 사용하는 것이 좋습니다. 다만, SSR(Server-Side Rendering) 환경에서 useLayoutEffect를 그대로 사용하면 경고가 발생하므로, 환경에 따라 안전하게 대체되는 useSafeLayoutEffect 패턴을 제안합니다.
import { useEffect, useLayoutEffect } from 'react'
const useSafeLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect| export function useScrollLock() { | ||
| useEffect(() => { |
개요
Modal 컴포넌트를 고도화했습니다. 본문이 길어질 때 제목과 버튼이 함께 스크롤돼 사라지던 문제를 해결하고, 모달이 열린 동안 배경이 스크롤되던 문제도 함께 고쳤습니다.
변경 사항
feat: 모달 고정 헤더/푸터 추가 및 본문 스크롤 분리
config.title/config.footer로 상단·하단 영역을 고정하고 가운데 본문(content)만 스크롤header/body/footer3영역으로 재구성body에min-height:0+overflow-y:auto로 스크롤 영역 격리 (모달 전체overflow:hidden)role="dialog"를 backdrop → 모달 박스로 이동,title지정 시aria-labelledby연결 (접근성 보강)content-only 사용과 하위 호환 유지 (title/footer미지정 시 종전 동작)feat: 오버레이 배경 스크롤 잠금 추가
useScrollLock훅 신설 — 모달/다이얼로그가 열린 동안body스크롤 잠금padding-right보정으로 배경 밀림(레이아웃 이동) 방지docs
modal.md: title/footer API, 고정 헤더/푸터, 스크롤 잠금, 접근성 섹션 및 API 표 갱신커밋 구성
참고
src/styles/token.semantic.css(Tabs 토큰)는 이번 작업과 무관한 별도 변경이라 포함하지 않았습니다.🤖 Generated with Claude Code