CSS容器查詢實戰:5個模式構建元件級響應式佈局
前端工程
容器查詢:響應式設計的範式轉移
媒體查詢(@media)基於視埠寬度響應——同一元件在側邊欄和主內容區表現相同,無法根據自身容器大小適配。**CSS容器查詢(@container)**讓元件根據父容器尺寸響應,真正實現「元件級響應式」。2026年,Container Queries已被所有主流瀏覽器支援,Container Query Units(cqw/cqh)成為新的響應式單位,元件庫不再需要斷點Props。
本文將從5種核心模式出發,帶你完成容器定義→元件查詢→容器單位→巢狀容器→實戰元件的全鏈路實戰。
核心概念
| 概念 | 說明 |
|---|---|
| @container | 基於容器尺寸的CSS查詢規則 |
| container-type | 定義容器型別(inline-size/size/normal) |
| container-name | 命名容器,用於精確查詢 |
| cqw/cqh | 容器查詢寬度/高度單位(1cqw = 容器寬度的1%) |
| container | container-type和container-name的簡寫 |
| inline-size | 僅查詢行內方向(寬度)的容器型別 |
| size | 查詢寬度和高度的容器型別 |
| style() | 基於容器CSS自訂屬性的查詢 |
問題分析:容器查詢的5大挑戰
- 容器型別選擇:inline-size vs size對效能的影響
- 巢狀容器:多層容器查詢的優先級和效能
- 回退策略:不支援容器查詢的瀏覽器降級
- 與媒體查詢配合:何時用容器查詢、何時用媒體查詢
- 容器查詢單位:cqw/cqh與rem/vw的混用問題
分步實操:5種容器查詢模式
模式1:基礎容器查詢
/* 定義容器 */
.card-container {
container-type: inline-size;
container-name: card;
}
/* 預設樣式:窄容器 */
.card {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
.card-image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.card-content {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
/* 寬容器:水平佈局 */
@container card (min-width: 400px) {
.card {
flex-direction: row;
align-items: center;
}
.card-image {
width: 200px;
aspect-ratio: 1;
flex-shrink: 0;
}
.card-content {
flex: 1;
}
}
/* 更寬容器:大卡片 */
@container card (min-width: 600px) {
.card {
padding: 1.5rem;
gap: 1.5rem;
}
.card-image {
width: 280px;
}
.card-title {
font-size: 1.5rem;
}
}
模式2:容器查詢單位
/* 使用容器查詢單位實現流式排版 */
.text-container {
container-type: inline-size;
}
.fluid-heading {
font-size: clamp(1.2rem, 5cqw, 3rem);
line-height: 1.2;
}
.fluid-body {
font-size: clamp(0.875rem, 2.5cqw, 1.125rem);
line-height: 1.6;
}
.fluid-spacing {
padding: clamp(0.75rem, 3cqw, 2rem);
gap: clamp(0.5rem, 2cqw, 1.5rem);
}
/* 容器查詢+clamp實現無斷點響應 */
.adaptive-grid {
container-type: inline-size;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
gap: clamp(0.75rem, 2cqw, 1.5rem);
}
/* 響應式排版系統 */
:root {
--font-scale: 1;
}
.typography-container {
container-type: inline-size;
}
@container (min-width: 300px) {
.typography-container { --font-scale: 1.1; }
}
@container (min-width: 500px) {
.typography-container { --font-scale: 1.25; }
}
@container (min-width: 700px) {
.typography-container { --font-scale: 1.4; }
}
.responsive-text {
font-size: calc(1rem * var(--font-scale));
}
模式3:命名容器與巢狀
/* 命名容器:精確控制查詢目標 */
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main-content {
container-type: inline-size;
container-name: main;
}
.widget {
container-type: inline-size;
container-name: widget;
}
/* 側邊欄內的導航 */
@container sidebar (min-width: 250px) {
.nav-item {
flex-direction: row;
gap: 0.75rem;
}
.nav-icon {
width: 20px;
}
.nav-label {
display: block;
font-size: 0.875rem;
}
}
@container sidebar (max-width: 249px) {
.nav-item {
flex-direction: column;
align-items: center;
}
.nav-label {
font-size: 0.75rem;
}
}
/* 巢狀容器:widget在sidebar內 */
@container widget (min-width: 200px) {
.widget-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@container widget (max-width: 199px) {
.widget-grid {
grid-template-columns: 1fr;
}
}
模式4:容器查詢+元件庫
/* 元件庫:無斷點Props的響應式元件 */
.btn-container {
container-type: inline-size;
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
font-size: 0.875rem;
white-space: nowrap;
}
.btn-icon {
width: 1rem;
height: 1rem;
flex-shrink: 0;
}
.btn-label {
overflow: hidden;
text-overflow: ellipsis;
}
/* 窄容器:只顯示圖示 */
@container (max-width: 100px) {
.btn {
padding: 0.5rem;
}
.btn-label {
display: none;
}
}
/* 中等容器:圖示+短文字 */
@container (min-width: 101px) and (max-width: 200px) {
.btn {
padding: 0.5rem 0.75rem;
}
.btn-label {
max-width: 6ch;
}
}
/* 寬容器:完整顯示 */
@container (min-width: 201px) {
.btn {
padding: 0.5rem 1.25rem;
}
}
/* 響應式表單元件 */
.form-field-container {
container-type: inline-size;
}
.form-field {
display: flex;
flex-direction: column;
gap: 0.375rem;
}
@container (min-width: 400px) {
.form-field {
flex-direction: row;
align-items: center;
}
.form-label {
width: 120px;
flex-shrink: 0;
text-align: right;
}
.form-input {
flex: 1;
}
}
模式5:容器樣式查詢(@container style())
/* 基於自訂屬性的樣式查詢 */
.theme-container {
container-type: inline-size;
--theme: light;
}
.theme-container[data-theme="dark"] {
--theme: dark;
}
/* 根據主題變數切換樣式 */
@container style(--theme: dark) {
.themed-card {
background: #1f2937;
color: #f9fafb;
border-color: #374151;
}
.themed-card:hover {
background: #111827;
}
}
@container style(--theme: light) {
.themed-card {
background: #ffffff;
color: #111827;
border-color: #e5e7eb;
}
.themed-card:hover {
background: #f9fafb;
}
}
/* 基於佈局變數切換 */
.layout-container {
container-type: inline-size;
--layout: compact;
}
.layout-container[data-layout="comfortable"] {
--layout: comfortable;
}
@container style(--layout: compact) {
.list-item {
padding: 0.5rem;
gap: 0.5rem;
}
}
@container style(--layout: comfortable) {
.list-item {
padding: 1rem;
gap: 1rem;
}
}
避坑指南
坑1:忘記設定container-type
/* ❌ 錯誤:未定義容器型別,@container不生效 */
.parent { }
@container (min-width: 400px) { .child { ... } }
/* ✅ 正確:先定義容器型別 */
.parent { container-type: inline-size; }
@container (min-width: 400px) { .child { ... } }
坑2:size型別效能問題
/* ❌ 錯誤:不需要高度查詢卻用size */
.container { container-type: size; }
/* ✅ 正確:只查寬度用inline-size */
.container { container-type: inline-size; }
坑3:容器查詢與媒體查詢衝突
/* ❌ 錯誤:容器查詢和媒體查詢互相覆蓋 */
@media (min-width: 768px) { .card { flex-direction: row; } }
@container (min-width: 400px) { .card { flex-direction: column; } }
/* ✅ 正確:媒體查詢管佈局框架,容器查詢管元件內部 */
@media (min-width: 768px) { .sidebar { width: 300px; } }
@container (min-width: 400px) { .card { flex-direction: row; } }
坑4:容器查詢單位溢位
/* ❌ 錯誤:cqw沒有clamp限制,極端情況溢位 */
.title { font-size: 5cqw; }
/* ✅ 正確:用clamp限制範圍 */
.title { font-size: clamp(1rem, 5cqw, 3rem); }
坑5:巢狀容器查詢目標錯誤
/* ❌ 錯誤:未命名容器,查詢匹配到錯誤的祖先 */
.outer { container-type: inline-size; }
.inner { container-type: inline-size; }
@container (min-width: 400px) { .item { ... } } /* 匹配到inner */
/* ✅ 正確:使用命名容器精確匹配 */
.outer { container-type: inline-size; container-name: outer; }
.inner { container-type: inline-size; container-name: inner; }
@container outer (min-width: 400px) { .item { ... } }
報錯排查
| 序號 | 報錯資訊 | 原因 | 解決方法 |
|---|---|---|---|
| 1 | @container not working |
未設定container-type | 新增container-type: inline-size |
| 2 | cqw unit not applied |
瀏覽器不支援 | 檢查瀏覽器版本或新增fallback |
| 3 | Container query matches wrong element |
巢狀容器未命名 | 使用container-name區分 |
| 4 | Layout shift on container change |
容器尺寸變化導致重排 | 新增transition平滑過渡 |
| 5 | Performance degradation |
container-type: size開銷大 | 改用inline-size |
| 6 | style() query not supported |
瀏覽器不支援樣式查詢 | 使用data-attribute替代 |
| 7 | Container query ignored in Shadow DOM |
Shadow DOM邊界問題 | 在Shadow DOM內定義容器 |
| 8 | Flex item container not queried |
Flex子項寬度不確定 | 設定min-width: 0 |
| 9 | Container query breaks grid |
Grid子項容器寬度不確定 | 使用minmax()約束 |
| 10 | Safari container query bug |
Safari特定版本Bug | 更新Safari或新增polyfill |
進階最佳化
- 無斷點設計:用cqw+clamp替代固定斷點,實現流式響應
- 元件Token:容器查詢+CSS自訂屬性實現元件級主題
- 容器查詢Polyfill:使用Container Query Polyfill支援舊瀏覽器
- PostCSS轉換:PostCSS外掛自動生成媒體查詢回退
- 設計系統整合:元件庫統一使用容器查詢替代斷點Props
對比分析
| 維度 | 容器查詢 | 媒體查詢 | Element Queries | JS Resize |
|---|---|---|---|---|
| 查詢目標 | 父容器 | 視埠 | 元素自身 | 元素自身 |
| CSS原生 | ✅ | ✅ | ❌ | ❌ |
| 效能 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| 元件級 | ✅ | ❌ | ✅ | ✅ |
| 巢狀支援 | ✅ | ✅ | ❌ | ✅ |
| 瀏覽器支援 | 主流 | 全部 | 需Polyfill | 全部 |
總結:CSS容器查詢讓響應式設計從「頁面級」進化為「元件級」,元件不再依賴視埠寬度,而是根據自身容器空間自適應。inline-size容器+命名容器+cqw單位三位一體,讓元件庫徹底告別斷點Props。2026年容器查詢已成為響應式設計的新標準,與媒體查詢各司其職:媒體查詢管頁面佈局,容器查詢管元件內部。
線上工具推薦
- JSON格式化:/zh-TW/json/format
- Hash計算:/zh-TW/encode/hash
- cURL轉程式碼:/zh-TW/dev/curl-to-code
本站提供瀏覽器本地工具,免註冊即可試用 →
#容器查询#响应式设计#CSS Container Query#组件级响应#2026#前端工程