C.W.K.
Stream
Lesson 02 of 05 · published

Container Query: 컨테이너에 적응하는 component

~12 min · container-queries, responsive, component-driven

Level 0Markup Novice
0 XP0/34 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Media query 가 'viewport 가 얼마나 커?' 물어. Container query 가 '*이* 부모가 얼마나 커?' 물어. 그 단일 전환이 component 를 실제로 재사용 가능하게 만들어."

Container query 가 해결하는 문제

아름다운 카드 component 짓는다. 홈페이지의 풀 너비에서 멋져. 같은 카드를 280px 사이드바에 넣어 — 이미지가 너무 크고, 텍스트가 이상하게 wrap, CTA 버튼이 fit 안 됨. 카드가 viewport 때문이 아니라 컨테이너 때문에 깨짐.

Container query 전엔, 유일한 fix 가 "사이드바 variant" CSS 적기 또는 viewport media query 의존 (같은 viewport 가 카드를 두 다른 컨텍스트에 호스팅하면 실패). Container query 가 component 로 하여금 "나 얼마나 넓게 렌더 중?" 묻고 적응 — 주변 무관.

두 단계 패턴

Container query 가 항상 두 조각 포함:

  1. 쿼리될 부모에 containment 컨텍스트 선언. container-type 사용.
  2. 그 컨테이너를 자손 안에서 쿼리@container 사용.

1 단계: container-type

  • container-type: inline-size — 컨테이너의 inline 크기 쿼리 (LTR 의 너비). 가장 흔함. 컨테이너 크기가 자기 너비로 결정; 자손이 그 너비 쿼리 가능.
  • container-type: size — inline 과 block 둘 다 쿼리 (너비 AND 높이). 컨테이너 크기가 self-determining 됨 — 자식 크기에 안 맞춰짐, 조심해, 컨테이너가 collapse 할 수 있어.
  • container-type: normal — 컨테이너 아님, 쿼리 불가 (기본).

거의 항상 inline-size 사용. size 는 특화된 케이스 (알려진 고정 높이 컨테이너) 용.

2 단계: @container

자손 안에서, 가장 가까운 containment 컨텍스트 쿼리:

명료성 위해 컨테이너 명명

Component 가 컨테이너 중첩할 때, 명명이 모호함 피함. 아니면 @container 가 container type 가진 가장 가까운 ancestor 쿼리:

Container query unit: cqw, cqh, cqi, cqb

vwvh 가 viewport unit 인 것처럼, container query unit 이 컨테이너 기준 측정:

  • cqw — 컨테이너 너비의 1%.
  • cqh — 컨테이너 높이의 1%.
  • cqi — 컨테이너 inline 크기의 1% (= LTR 의 cqw).
  • cqb — 컨테이너 block 크기의 1% (= 수평 writing-mode 의 cqh).
  • cqmin, cqmax — cqi 와 cqb 의 min/max.

이게 viewport 가 아니라 컨테이너 기준으로 sizing 하게 — component 를 진짜 self-contained 로 만듦.

주의: Container type 이 layout 행동 바꿈

container-type: inline-size 가 containment 컨텍스트 설정, layout 이 컨테이너와 상호작용하는 방식에 영향. 구체적으로, 컨테이너가 absolute positioned 자손의 containing block 이 되고, 특정 layout 최적화 적용. 보통 보이지 않음; 가끔 미묘한 layout 변화 봄. Fix 는 layout 에 다른 영향 안 주는 wrapper 에 container-type 적용.

Container query 가 component 를 진짜 재사용 가능하게 만들어. 컨테이너에 적응하는 카드가 280px 사이드바, 600px main column, 1200px hero 에서 같은 행동 — 어떤 "이 컨텍스트에서" variant CSS 없이. Component 가 적응의 단위지 viewport 가 아냐.

브라우저 지원

Container query 가 baseline 2023, 모든 주요 브라우저 (Chrome, Edge, Safari, Firefox) 지원. cq* unit 도 baseline. 2026 년에 polyfill 필요 없음.

Container query vs media query 쓸 때

  • Media query: 페이지 레벨 구조. "데스크톱 너비에서 사이드바 보임." 사이트 전역 패턴. 사용자 선호.
  • Container query: component 레벨 적응. "컨테이너가 > 400px 일 때 카드가 stack 에서 horizontal layout 으로 전환."

대부분 실제 앱이 둘 다 사용. 페이지 셸이 viewport 에 응답 (media query); 안의 카드가 컨테이너에 응답 (container query).

피파의 노트

Cwk-site quest 카드가 container query 가짐: < 320px (좁은 사이드바) 에선 title 만 보여 줌; 320-480px 엔 title + thumbnail; > 480px 엔 description 과 difficulty 가진 풀 카드. 같은 React component 가 세 컨텍스트에 맞게 렌더: 홈페이지 hero (wide), 추천 사이드바 (medium), 검색 결과 column (narrow). Variant component 0, "사이드바 variant 야?" props 0. Component 가 컨테이너 묻고; 컨테이너가 답.

Code

Container query 기본·css
/* 1 단계: 부모를 query 컨테이너로 선언 */
.card-wrapper {
  container-type: inline-size;
  /* Wrapper 가 이제 containment 컨텍스트 정의 */
}

/* 2 단계: 안에서 컨테이너 쿼리 */
.card {
  display: grid;
  grid-template-columns: 1fr;     /* 기본 stacked */
  gap: 1rem;
  padding: 1rem;
}

@container (width >= 400px) {
  .card {
    grid-template-columns: 120px 1fr;  /* 컨테이너 400+ 일 때 horizontal */
  }
}

@container (width >= 600px) {
  .card {
    grid-template-columns: 180px 1fr auto;  /* action 위해 3 번째 column 추가 */
    padding: 1.5rem;
  }
}
명명된 컨테이너·css
/* 명명된 컨테이너 — component 중첩 시 유용 */
.layout {
  container-type: inline-size;
  container-name: layout;
}

.card-wrapper {
  container-type: inline-size;
  container-name: card;
}

/* 특정 명명된 컨테이너 쿼리 */
@container card (width >= 400px) {
  .card { /* ... */ }
}

@container layout (width >= 768px) {
  .layout-aside { display: block; }
}

/* container 약자 */
.named {
  container: my-context / inline-size;   /* 이름 / type */
}
Container query unit·css
/* Container query unit: 컨테이너 기준 크기 */
.card-wrapper {
  container-type: inline-size;
}

.card {
  padding: 5cqw;                /* 컨테이너 너비의 5% */
  font-size: clamp(1rem, 3cqi, 1.5rem);  /* 유연한 type, 컨테이너 기준 */
  gap: 2cqw;
}

.card .hero-image {
  height: 50cqw;                /* 16:9-ish 이미지, 컨테이너 인식 */
}

/* Viewport unit (vw, vh) 와 비교:
   vw 가 페이지로 스케일; cqw 가 부모 컨테이너로 스케일.
   padding: 5vw 가진 카드가 사이드바에선 작고 hero 에선 거대.
   padding: 5cqw 가진 카드가 둘 다 맞음. */

External links

Exercise

컨테이너 너비 기반 적응하는 카드 component 짓기: < 300px (title 만), 300-500px (title + thumbnail), > 500px (title + thumbnail + description + CTA). 같은 페이지의 세 컨텍스트에 같은 카드 렌더: 280px 사이드바, 600px main column, 풀 너비 hero. 카드가 각 컨텍스트에 맞게 적응하는지 확인, 다 같은 viewport 너비에서.
Hint
각 카드 인스턴스를 container-type: inline-size 가진 div 로 wrap. 카드의 CSS 안에서 @container query 써서 선택한 breakpoint 에 layout 전환. 카드 component 자체는 어느 컨텍스트인지 알 필요 없음 — 그냥 컨테이너 쿼리.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.