본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Frontend

CSS 오버플로와 스크롤: 넘침 처리와 스크롤 스냅

작성 2026. 10. 17.추가
목차7개 항목
출처와 참고

web.dev의 「Learn CSS」 강좌의 Overflow 모듈을 바탕으로, 스크롤바 속성의 브라우저 지원은 MDN으로 확인해 재구성한 노트다.

오버플로란

오버플로(overflow)는 내용이 박스에 정해진 크기보다 클 때 생긴다. 부모를 크기가 고정된 창문, 자식을 창 너머 풍경이라고 생각하면 된다. 지도처럼 의도한 넘침도 있고, 채팅 말풍선에 긴 URL이 들어오는 것처럼 의도하지 않은 넘침도 있다.

넘침 처리 도구는 두 가지다.

도구대상
overflow 계열박스 전체의 넘침(주로 블록 방향)
text-overflow한 줄 텍스트의 넘침(인라인 방향)

overflow 값

값넘친 내용스크롤바스크롤 가능
visible (기본)박스 밖으로 보인다없음-
hidden패딩 상자에서 잘린다없음스크립트로는 가능
clip잘린다없음불가(스크립트 포함)
scroll잘린다넘치지 않아도 항상가능
auto잘린다넘칠 때만가능
.panel { overflow: hidden auto; }   /* 두 값이면 x → y 순 */
  • 기본값이 visible인 이유는 내용을 실수로 숨기지 않기 위해서다. 잘리는 것보다 겹치는 것이 데이터 손실이 적다.
  • 대부분은 auto가 맞다. 필요할 때만 스크롤바가 나타난다.
  • scroll은 나중에 넘칠 수 있는 영역의 스크롤바 자리를 미리 잡아 레이아웃 이동을 막는다. 자리만 잡고 싶다면 scrollbar-gutter: stable도 있다.
  • visible·clip 외의 값은 새 블록 서식 맥락(BFC)을 만든다. 안의 float를 품고 margin 병합을 막는다(박스 모델과 display).
  • overflow: hidden인 조상 안에서는 position: sticky가 그 조상을 스크롤 컨테이너로 삼아 기대대로 붙지 않는다. 넘침만 자르려면 스크롤 컨테이너를 만들지 않는 clip을 쓴다.
  • 축별 속성은 물리(overflow-x, overflow-y)와 논리(overflow-inline, overflow-block) 둘 다 있다. 논리 판은 Chrome 135부터 들어가 모든 주요 브라우저가 지원한다.

한 줄 말줄임

.ellipsis {
  overflow: hidden;
  white-space: nowrap;      /* 한 줄로 */
  text-overflow: ellipsis;  /* 잘린 자리에 … */
}
.clamp-3 {                  /* 여러 줄 말줄임 */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

세 줄이 모두 있어야 한다. 말줄임이 안 되면 요소의 너비가 제한되지 않은 것이다. 플렉스 아이템 안이라면 min-width: 0이 빠졌을 가능성이 크다(Flexbox의 넘침 함정). 긴 단어·URL이 박스를 뚫는 문제는 overflow-wrap: anywhere로 푼다(웹 타이포그래피).

스크롤 영역과 접근성

마우스 사용자는 휠로 스크롤하지만, 키보드 사용자는 스크롤 영역에 포커스가 가야 방향키로 움직일 수 있다. 포커스 가능한 자식이 없는 스크롤 영역은 이름과 역할을 붙여 포커스를 받게 한다.

<div class="code-block" tabindex="0" role="region" aria-labelledby="code-caption">…</div>
/* 속성이 다 갖춰졌을 때만 스크롤을 켠다: 접근성 회귀를 CSS로 막는 패턴 */
[role][aria-labelledby][tabindex] { overflow: auto; }
[role][aria-labelledby][tabindex]:focus-visible { outline: .15em solid; }
  • 스크롤바는 패딩 상자 안에 자리를 차지한다. 화면 위에 겹치는 오버레이 스크롤바(모바일, macOS 기본)는 자리를 차지하지 않아 OS마다 레이아웃이 달라질 수 있다.
  • 모바일의 당겨서 새로고침, 바운스 같은 특수 동작은 문서의 루트 스크롤러에만 붙는다. 페이지 전체를 감싼 div를 스크롤시키면 이 동작이 사라진다. 가능하면 문서 자체가 스크롤되게 둔다.

스크롤 동작 다루기

속성하는 일
scrollbar-color: 손잡이 트랙스크롤바 색. Safari는 26.2부터 지원
scrollbar-widthauto, thin, none만 가능. 임의 길이는 안 된다. Safari 18.2부터 지원
scroll-behavior: smooth앵커 링크·scrollTo() 이동을 부드럽게
overscroll-behavior: contain끝까지 스크롤한 뒤 스크롤이 부모로 이어지는 것(scroll chaining) 을 막는다. 모달 끝에서 뒤 페이지가 움직이는 문제
scroll-padding스크롤 컨테이너 쪽 여백. 고정 헤더에 앵커 대상이 가려질 때
scroll-margin대상 요소 쪽 여백. 스크롤해 갔을 때 위에 남길 공간
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }        /* 움직임을 줄이고 싶은 사용자에게는 즉시 이동 */
}
html { scroll-padding-top: 4rem; }         /* 4rem 높이 고정 헤더 */
.modal-body { overflow: auto; overscroll-behavior: contain; }

스크롤 스냅

갤러리·슬라이드처럼 스크롤이 칸마다 멈추게 한다. 컨테이너와 자식에 나눠 준다.

.carousel {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: inline mandatory;   /* 축 + 엄격도 */
  scroll-padding-inline: 1rem;
}
.carousel > .slide {
  flex: 0 0 80%;
  scroll-snap-align: center;            /* start | center | end */
  scroll-snap-stop: always;             /* 빠르게 넘겨도 다음 칸에서 일단 멈춘다 */
}
속성위치값
scroll-snap-type컨테이너축 x·y·block·inline·both + proximity(기본, 가까우면 붙음) 또는 mandatory(항상 붙음)
scroll-snap-align자식자식의 어느 가장자리를 스크롤 영역에 맞출지. both면 두 값
scroll-snap-stop자식always면 관성 스크롤도 다음 스냅 지점에서 멈춘다
scroll-padding / scroll-margin컨테이너 / 자식스냅 위치 보정

mandatory는 칸이 화면보다 클 때 칸 사이 내용에 도달할 수 없게 만들 수 있다. 다양한 화면 크기에서 시험한다.

정리

  • 기본은 visible. 스크롤 영역에는 대개 auto, 스크롤 없이 자르기만 하려면 clip.
  • 한 줄 말줄임은 overflow: hidden + white-space: nowrap + text-overflow: ellipsis.
  • 포커스 가능한 자식이 없는 스크롤 영역은 tabindex="0"·role·이름을 준다.
  • 부드러운 스크롤은 prefers-reduced-motion을 확인하고 켠다. 스크롤 체이닝은 overscroll-behavior: contain.
  • 칸마다 멈추는 스크롤은 scroll-snap-type + scroll-snap-align. mandatory는 내용이 잘리지 않는지 확인한다.

관련 노트: 박스 모델과 display, Float와 Flexbox 레이아웃, 웹 타이포그래피: 가독성, 글줄 길이, 웹폰트, 커서와 포인터 입력, 접근성을 위한 CSS와 타이포그래피

원본 기록3

댓글

GitHub 계정으로 댓글을 남길 수 있어요.