contain
이 요소의 내부 변화가 바깥에 영향을 주지 않는다고 브라우저에 약속하는 성능 최적화 속성입니다. 그 약속 덕분에 브라우저는 레이아웃·페인트 계산을 이 요소 안에서 끊을 수 있습니다. ctnp는 페인트 격리, ctnst는 최대 격리를 적용합니다.
클래스 목록
| 클래스 | CSS | 설명 |
|---|---|---|
ctnn | contain: none | 격리 없음 (기본값) |
ctnc | contain: content | layout + paint 격리 |
ctns | contain: size | 크기 격리 (자식이 부모 크기에 영향 없음) |
ctnl | contain: layout | 레이아웃 격리 |
ctnp | contain: paint | 페인트 격리 (자식이 경계 밖으로 그려지지 않음) |
ctnst | contain: strict | size + layout + paint 전체 격리 |
시각 데모
contain은 눈에 보이는 효과가 거의 없지만, paint 격리만은 예외입니다. 두 상자와 그 안의 자식은 크기·위치가 완전히 같고 클래스 하나만 다릅니다.
none — ctnn
자식이 상자 밖으로 그대로 삐져나옵니다.
paint — ctnp
패딩 박스 경계에서 잘려 나갑니다.
<!-- Identical boxes and identical oversized children -->
<div class="w100p h10rem br8px bg18181B ctnn">
<div class="w150p h6rem mt6rem ml4rem bg6366F1 br8px"></div>
</div>
<div class="w100p h10rem br8px bg18181B ctnp">
<div class="w150p h6rem mt6rem ml4rem bg38BDF8 br8px"></div>
</div>클래스별 상세
ctnncontain: none
기본값이며 아무 격리도 하지 않습니다. 공용 컴포넌트가 걸어 둔 격리를 특정 인스턴스에서만 되돌릴 때 명시적으로 씁니다.
<!-- Explicitly opt an element out of an inherited containment class -->
<div class="ctnn">
Nothing is contained here.
</div>ctnlcontain: layout
내부 레이아웃이 바깥 레이아웃에 영향을 주지 않는다고 선언합니다. 자식이 아무리 재배치되어도 형제나 조상은 다시 계산되지 않습니다. 대신 이 요소는 새로운 포함 블록이자 쌓임 맥락이 되고, 마진 상쇄도 일어나지 않습니다.
<!-- The internal layout of this widget can never move anything outside it -->
<div class="ctnl p2rem bg18181B br8px">
<p>Rearranging children re-lays out only this box.</p>
</div>ctnpcontain: paint
자식이 패딩 박스 밖으로 그려지지 않는다고 선언합니다. 실제로 잘려 나가므로 결과만 보면 overflow: hidden과 비슷하지만, 목적은 화면 밖 요소의 페인트를 통째로 건너뛰게 만드는 것입니다. layout 격리의 부수 효과도 함께 따라옵니다.
<!-- Nothing inside can paint outside the padding box -->
<div class="ctnp h10rem br8px bg18181B">
<div class="w32rem">This wide child is clipped.</div>
</div>ctnscontain: size
자식이 요소의 크기에 관여하지 못하게 합니다. 브라우저는 내용을 보지 않고 크기를 정하므로, 높이를 지정하지 않으면 박스가 0으로 접힙니다. 넷 중 가장 위험한 값입니다.
<!-- The box must carry its own dimensions -->
<div class="ctns h20rem w100p bg18181B br8px">
<p>Content no longer contributes to the size.</p>
</div>반드시 크기를 함께 지정하세요
size 격리는 명시적인 width/height 또는 aspect-ratio와 짝지어야 합니다. 그렇지 않으면 요소가 사라진 것처럼 보입니다.
ctnccontain: content
layout + paint + style을 한 번에 켜는 실무용 기본값입니다. size 격리가 빠져 있어 크기는 내용이 정하므로, 카드·위젯·댓글 항목처럼 높이가 유동적인 블록에 안전하게 쓸 수 있습니다.
<!-- Independent card widget: layout + paint + style -->
<div class="ctnc p2rem bg18181B br8px">
<h3>Widget title</h3>
<p>Changes to this card do not affect the outside.</p>
</div>ctnstcontain: strict
content에 size 격리까지 더한 최대 격리입니다. 화면 밖 요소의 작업을 통째로 건너뛸 수 있어 가장 빠르지만, 크기를 직접 지정해야 하므로 높이가 고정된 리스트 행처럼 조건이 맞는 곳에만 쓰세요.
<!-- Fully isolated: size + layout + paint + style -->
<div class="ctnst h10rem oh">
<p>The browser can skip this subtree entirely when off screen.</p>
</div>실전 예시
<!-- Independent card widget -->
<div class="ctnc p2rem bg18181B br8px">
<h3>Widget title</h3>
<p>Changes to this card do not affect the outside.</p>
</div>
<!-- Long list item requiring performance optimization -->
<div class="ctnst h10rem oh">
<p>Fully isolated element</p>
</div>행 높이가 일정한 긴 리스트가 strict 격리의 교과서적인 사용처입니다.
<!-- Feed of a few thousand rows. Each row is a fixed height,
so size containment is safe and the browser can skip
layout and paint for everything scrolled off screen. -->
<ul class="lsn p0 m0">
<li class="ctnst h8rem df aic gap16px px16px bb1pxsolid27272A">
<img src="/avatar.jpg" class="w4rem h4rem br50p" alt="" />
<div>
<p class="fs14px cFAFAFA fw600">Row title</p>
<p class="fs12px c71717A">Secondary line</p>
</div>
</li>
<!-- ... a few thousand more ... -->
</ul>
<!-- Third-party embed: keep its layout from disturbing the page -->
<div class="ctnc br8px oh b1pxsolid27272A">
<iframe src="https://example.com/embed" class="w100p h30rem bn"></iframe>
</div>언제 뭘 쓸까?
| 상황 | 추천 |
|---|---|
| 독립적인 위젯/카드 | ctnc |
| 오프스크린 요소 최적화 | ctnst |
| overflow: hidden 대체 | ctnp |
| 레이아웃 재계산 방지 | ctnl |
팁 / 주의사항
성능 도구이지 레이아웃 도구가 아닙니다
잘라내고 싶어서 ctnp를 쓰는 것은 잘못된 선택입니다. 그 용도에는 overflow가 맞습니다. contain은 측정 가능한 성능 문제가 있을 때 꺼내는 카드이며, 아무 데나 뿌리면 오히려 예상 못한 레이아웃 변화를 만듭니다.
안쪽의 sticky · fixed 요소가 깨집니다
layout이나 paint 격리는 새로운 포함 블록을 만듭니다. 그래서 내부의 position: fixed 요소는 뷰포트가 아니라 이 상자를 기준으로 붙고, sticky 헤더는 상자 밖으로 나가지 못해 따라붙지 않는 것처럼 보입니다.
드롭다운과 툴팁이 잘립니다
paint 격리가 걸린 카드 안에서 열리는 메뉴·툴팁·팝오버는 경계에서 잘려 나갑니다. 이런 UI가 있는 컨테이너에는 ctnp나 그것을 포함하는 ctnc·ctnst를 쓰지 마세요.
격리된 박스는 스크롤 앵커링과 접근성에도 영향을 줍니다
size 격리를 건 요소는 내용이 없는 것처럼 크기가 계산되므로, 내용이 늦게 들어오면 스크롤 위치가 튀거나 화면 밖 요소의 크기가 0으로 보고됩니다.
content-visibility가 더 나은 선택일 때가 많습니다
화면 밖 렌더링을 건너뛰는 것이 목적이라면 content-visibility: auto가 필요한 격리를 알아서 적용하고 크기 힌트까지 받아줍니다. strict 격리를 손으로 거는 것보다 안전합니다.