컨테이너 쿼리

Container queries

뷰포트 크기가 아니라 "자기 부모 컨테이너의 크기"에 반응해 스타일이 바뀌는 CSS 기능. 같은 카드가 놓인 자리에 따라 알아서 레이아웃을 바꿉니다.

다른 이름: @containerComponent-level responsiveness
···
html
<div class="box" id="box">
  <div class="card">
    <div class="thumb"></div>
    <div class="text"><i class="ln l1"></i><i class="ln l2"></i></div>
  </div>
</div>
css
.box{width:200px;max-width:92%;height:min(78%,220px);border:2px dashed var(--muted);border-radius:10px;
  padding:10px;container-type:inline-size;transition:width 2.4s cubic-bezier(.4,0,.2,1);overflow:hidden}
.card{height:100%;background:var(--surface);border:1px solid var(--line);border-radius:10px;overflow:hidden;
  display:flex;flex-direction:column}
.thumb{flex:1;background:linear-gradient(135deg,var(--accent),var(--accent-3));min-height:40%}
.text{padding:10px;display:flex;flex-direction:column;gap:8px;justify-content:center}
.ln{display:block;height:8px;border-radius:3px;background:var(--line)}
.l1{width:70%}.l2{width:46%}
@container (min-width: 340px){
  .card{flex-direction:row}
  .thumb{min-height:100%;width:42%}
  .text{flex:1}
}
js
const box = document.getElementById('box');
box.style.width = '200px';
let wide = false;
function toggle() {
  wide = !wide;
  box.style.width = wide ? '460px' : '200px';
  setTimeout(toggle, 2600);
}
setTimeout(toggle, 2200);

`@media`는 브라우저 창 크기만 봅니다. 그래서 같은 카드 컴포넌트를 넓은 메인 영역에 놓든 좁은 사이드바에 놓든 스타일이 똑같이 적용돼서, 좁은 자리에서는 내용이 찌그러지기 쉬웠습니다. `@container`는 그 카드가 "실제로 몇 px짜리 상자 안에 있는지"를 기준으로 스타일을 바꿉니다.

쓰는 법은 두 단계입니다. 부모에 `container-type: inline-size`를 줘서 "이 요소는 쿼리 대상이다"라고 선언하고, 자식에서 `@container (min-width: 400px) { … }`처럼 그 컨테이너의 폭 조건을 씁니다.

이제 정말로 "컴포넌트 단위 반응형"이 가능해졌다는 점에서 최근 CSS 중 가장 실용적인 기능으로 꼽힙니다. 2023년 기준 주요 브라우저에 모두 도입되어 실무에 바로 쓸 수 있습니다.

언제 쓰나

재사용 가능한 카드·위젯을 여러 폭의 자리(메인, 사이드바, 모달)에 두루 배치해야 할 때 필수입니다. 페이지 전체 레이아웃 전환에는 여전히 미디어 쿼리가 더 간단합니다.