Tailwind CSS v4의 네이티브 컨테이너 쿼리 지원, @container 변형, 기존 미디어 쿼리와의 비교, 그리고 컴포넌트 기반 반응형 디자인 패턴을 다룹니다.
4장에서 OKLCH 색상 시스템을 배웠습니다. 이 장에서는 Tailwind CSS v4가 네이티브로 지원하는 컨테이너 쿼리(Container Queries) 를 다룹니다. 컨테이너 쿼리는 뷰포트가 아닌 부모 컨테이너의 크기에 따라 스타일을 적용하는 CSS 기능으로, 진정한 컴포넌트 기반 반응형 디자인을 가능하게 합니다.
전통적인 반응형 디자인은 뷰포트 기반 미디어 쿼리를 사용합니다.
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
<div class="card">...</div>
<div class="card">...</div>
<div class="card">...</div>
</div>이 방식은 페이지 전체 레이아웃에는 잘 동작하지만, 재사용 가능한 컴포넌트에서는 문제가 됩니다. 같은 카드 컴포넌트가 전체 폭 영역, 사이드바, 모달 등 다양한 컨텍스트에 배치될 때, 뷰포트 크기만으로는 적절한 레이아웃을 결정할 수 없습니다.
뷰포트 1024px (md 이상)
├── 메인 영역 (700px) → 카드가 넓음 → 가로 레이아웃 적합
└── 사이드바 (300px) → 카드가 좁음 → 세로 레이아웃 필요
그러나 md: 변형은 두 영역 모두에 동일하게 적용됨
컨테이너 쿼리를 사용하려면 먼저 부모 요소를 컨테이너로 선언해야 합니다. Tailwind v4에서는 @container 클래스를 사용합니다.
<!-- 이 div가 컨테이너로 작동 -->
<div class="@container">
<!-- 자식 요소에서 컨테이너 크기 기반 스타일 적용 -->
<div class="@sm:flex @sm:gap-4">
<img class="@sm:w-48" src="..." alt="..." />
<div>
<h3 class="text-lg @md:text-xl">제목</h3>
<p class="@sm:line-clamp-2">설명...</p>
</div>
</div>
</div>Tailwind v4의 컨테이너 쿼리 브레이크포인트는 @ 접두사를 사용합니다.
| 변형 | 최소 너비 | CSS |
|---|---|---|
@xs | 320px | @container (min-width: 320px) |
@sm | 384px | @container (min-width: 384px) |
@md | 448px | @container (min-width: 448px) |
@lg | 512px | @container (min-width: 512px) |
@xl | 576px | @container (min-width: 576px) |
@2xl | 672px | @container (min-width: 672px) |
@3xl | 768px | @container (min-width: 768px) |
@4xl | 896px | @container (min-width: 896px) |
@5xl | 1024px | @container (min-width: 1024px) |
컨테이너 쿼리 브레이크포인트(@sm, @md 등)는 뷰포트 브레이크포인트(sm:, md: 등)와 다른 값을 가집니다. 컨테이너 브레이크포인트는 일반적으로 더 작은 값으로, 컴포넌트 수준의 크기 변화에 최적화되어 있습니다.
<div class="@container">
<div class="@[400px]:flex @[600px]:grid @[600px]:grid-cols-3">
<!-- 컨테이너가 400px 이상이면 flex, 600px 이상이면 3컬럼 그리드 -->
</div>
</div>여러 중첩된 컨테이너가 있을 때, 특정 컨테이너를 기준으로 쿼리할 수 있습니다.
<!-- sidebar라는 이름의 컨테이너 -->
<aside class="@container/sidebar">
<nav>
<!-- sidebar 컨테이너 크기에 반응 -->
<div class="@sm/sidebar:flex @sm/sidebar:gap-2">
<span class="@sm/sidebar:inline hidden">메뉴 텍스트</span>
</div>
</nav>
</aside>
<!-- main이라는 이름의 컨테이너 -->
<main class="@container/main">
<div class="@lg/main:grid @lg/main:grid-cols-2">
<!-- main 컨테이너 크기에 반응 -->
</div>
</main><div class="@container">
<article class="
flex flex-col
@sm:flex-row @sm:items-start
@md:items-center
gap-4
rounded-lg border p-4
">
<!-- 이미지: 컨테이너 크기에 따라 크기 변화 -->
<img
class="
w-full rounded-md object-cover
@sm:w-32 @sm:h-32
@md:w-48 @md:h-48
"
src="/thumbnail.jpg"
alt="포스트 썸네일"
/>
<div class="flex-1 space-y-2">
<h3 class="text-lg font-semibold @md:text-xl">포스트 제목</h3>
<p class="
text-sm text-muted
line-clamp-2
@md:line-clamp-3
@lg:line-clamp-none
">
포스트 설명이 여기에 들어갑니다. 컨테이너가 충분히 넓으면
전체 텍스트가 표시되고, 좁으면 줄임 처리됩니다.
</p>
<div class="
flex flex-wrap gap-2
@sm:flex-nowrap
">
<span class="text-xs text-muted">2026-03-25</span>
<span class="text-xs bg-primary/10 text-primary px-2 py-0.5 rounded">
Tailwind
</span>
</div>
</div>
</article>
</div>이 카드는 배치되는 컨테이너의 크기에 따라 자동으로 레이아웃이 변합니다.
<header class="@container">
<nav class="
flex flex-col items-center gap-2
@md:flex-row @md:justify-between
p-4
">
<div class="font-bold text-lg">Logo</div>
<ul class="
flex flex-wrap justify-center gap-1
@md:gap-4
">
<li><a class="px-3 py-1 @lg:px-4 @lg:py-2 rounded-md hover:bg-surface-alt" href="/">홈</a></li>
<li><a class="px-3 py-1 @lg:px-4 @lg:py-2 rounded-md hover:bg-surface-alt" href="/tech">기술</a></li>
<li><a class="px-3 py-1 @lg:px-4 @lg:py-2 rounded-md hover:bg-surface-alt" href="/about">소개</a></li>
</ul>
<div class="hidden @md:flex gap-2">
<button class="btn btn-primary">로그인</button>
</div>
</nav>
</header><section class="@container">
<div class="
grid gap-4
grid-cols-1
@sm:grid-cols-2
@lg:grid-cols-3
@3xl:grid-cols-4
">
<div class="card">항목 1</div>
<div class="card">항목 2</div>
<div class="card">항목 3</div>
<div class="card">항목 4</div>
</div>
</section>미디어 쿼리와 컨테이너 쿼리는 상호 보완적입니다. 페이지 레이아웃에는 미디어 쿼리를, 컴포넌트 내부 레이아웃에는 컨테이너 쿼리를 사용하는 것이 가장 효과적입니다.
<!-- 페이지 레이아웃: 미디어 쿼리 -->
<div class="grid grid-cols-1 lg:grid-cols-[1fr_300px] gap-6">
<!-- 메인 영역: 컨테이너 쿼리 -->
<main class="@container">
<div class="grid grid-cols-1 @md:grid-cols-2 @xl:grid-cols-3 gap-4">
<!-- 카드들은 메인 영역의 크기에 반응 -->
</div>
</main>
<!-- 사이드바: 컨테이너 쿼리 -->
<aside class="@container">
<!-- 같은 카드 컴포넌트지만 사이드바 크기에 맞게 적응 -->
</aside>
</div>설계 원칙: 페이지 레벨 레이아웃(그리드 컬럼 수, 사이드바 표시 여부 등)에는 미디어 쿼리(md:, lg:)를, 컴포넌트 레벨 레이아웃(카드 내부 배치, 텍스트 줄임 등)에는 컨테이너 쿼리(@sm:, @md:)를 사용하세요. 이렇게 하면 컴포넌트를 어디에 배치하든 올바르게 동작합니다.
기본 브레이크포인트가 프로젝트에 맞지 않는다면, @theme에서 커스텀 값을 정의할 수 있습니다.
@theme {
--container-3xs: 192px;
--container-2xs: 256px;
--container-xs: 320px;
--container-sm: 384px;
--container-md: 448px;
--container-lg: 512px;
--container-xl: 576px;
}컨테이너 쿼리는 반응형 디자인의 패러다임을 "뷰포트 중심"에서 "컴포넌트 중심"으로 전환합니다. Tailwind v4의 @container 클래스와 @sm:, @md: 변형은 이 강력한 CSS 기능을 유틸리티 클래스의 간결함으로 사용할 수 있게 합니다. 미디어 쿼리와 적절히 결합하면, 어떤 컨텍스트에서든 올바르게 동작하는 진정한 재사용 가능 컴포넌트를 만들 수 있습니다.
다음 장에서는 Tailwind v4에서 추가되거나 변경된 유틸리티 클래스와 변형(Variants)을 종합적으로 다룹니다.
이 글이 도움이 되셨나요?
관련 주제 더 보기
Tailwind CSS v4에서 추가, 변경, 제거된 유틸리티 클래스와 변형(Variants)을 종합 정리하고, 실전 활용 패턴을 다룹니다.
Tailwind CSS v4의 기본 색상 시스템인 OKLCH의 원리, 장점, 색상 팔레트 설계 방법, 그리고 투명도 수정자와 색상 조합 패턴을 실전 중심으로 다룹니다.
Tailwind CSS v4의 애니메이션 시스템, @keyframes 정의, @starting-style 활용, transition-behavior, 그리고 성능 최적화된 애니메이션 패턴을 다룹니다.