در حال بارگذاری...

کوئری کانتینر در CSS

Nesting سلکتورها را کنار هم نگه داشت. مدیا کوئری هنوز به viewport نگاه می‌کند. کوئری کانتینر سؤال دیگری می‌پرسد: عرضِ همین جعبهٔ والد چقدر است؟ همان کارت محصول در ریل باریک جمع‌وجور می‌ماند و در ستون اصلی باز می‌شود — حتی اگر پنجرهٔ مرورگر عوض نشده باشد.

چرا viewport کافی نیست

در خیلی از صفحه‌ها یک کامپوننت در جاهای نابرابر می‌نشیند: ریل کناری ۱۶rem و ناحیهٔ اصلیِ منعطف. هر دو جایگاهی یک عرض viewport دارند؛ پس @media (min-width: …) برای هر دو یک‌جور روشن می‌شود. باید استایل از کانتینری که دور کارت است بیاید، نه از کل صفحه.

زمینهٔ اندازه‌گیری بسازید

والدی را که باید اندازه‌اش گزارش شود انتخاب کنید. container-type را بگذارید — معمولاً inline-size تا بتوانید اندازهٔ این‌لاین والد را بپرسید (در نوشتن افقی همان عرض) بدون اینکه حتماً هر دو محور را قفل کنید:

Turn a rail into a size container

css
.rail {
container-type: inline-size;
container-name: rail;
width: 16rem;
padding: 1rem;
background: #f8fafc;
}

.stage {
container-type: inline-size;
container-name: stage;
flex: 1;
min-width: 0;
padding: 1.25rem;
}

بدون container-type، @container چیز قابل‌اتکایی برای اندازه گرفتن ندارد. container-name اختیاری است؛ وقتی چند والد کانتینر دارند، با اسم دقیق به یکی هدف می‌زنید.

با @container از والد بپرسید

بعد از این آماده‌سازی، قانون‌ها را داخل @container با شرط اندازه بپیچید. نوادگانِ آن کانتینر وقتی واکنش نشان می‌دهند که همان جعبه شرط را داشته باشد — نه لزوماً وقتی viewport عوض شود:

Product card reacts to its parent width

css
.product-card {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.75rem;
background: #fff;
}

.product-card .media {
aspect-ratio: 16 / 10;
border-radius: 0.5rem;
background: #cbd5e1;
}

.product-card .meta {
font-size: 0.875rem;
color: #64748b;
}

@container (min-width: 28rem) {
.product-card {
grid-template-columns: 10rem 1fr;
align-items: center;
}

.product-card .title {
font-size: 1.25rem;
}
}

اگر .product-card داخل .rail باریک باشد، همان چیدمان ستونی می‌ماند. همان HTML را در .stage پهن بگذارید؛ چیدمان دو ستونی باز می‌شود — یک مارک‌آپ، یک viewport، عرض کانتینر فرق دارد.

کانتینر نام‌دار

اگر چند کانتینر تو در تو دارید و معلوم نیست کدام عرض ملاک است، اسم را بعد از @container بنویسید:

Target a named containment context

css
@container stage (min-width: 36rem) {
.product-card {
grid-template-columns: 12rem 1fr auto;
gap: 1.25rem;
}

.product-card .buy {
justify-self: end;
}
}

@container rail (max-width: 18rem) {
.product-card .meta {
display: none;
}
}

@container stage (…) فقط به اجدادی با نام stage گوش می‌دهد. قانون‌های تنگِ ریل با قانون‌های جادارِ استیج قاطی نمی‌شوند.

واحدهای کوئری کانتینر

وقتی زمینهٔ containment هست، واحدهایی مثل cqi (یک‌درصد اندازهٔ این‌لاینِ کانتینرِ کوئری) و cqw (یک‌درصد عرضش) می‌گذارند تایپ و فاصله با والد رشد کنند، نه با viewport (vi / vw):

Type that tracks the container

css
.product-card .title {
font-size: clamp(1rem, 0.85rem + 2.5cqi, 1.5rem);
}

.product-card {
padding: clamp(0.75rem, 2.5cqi, 1.5rem);
}

این‌ها را با var() و clamp() درس‌های قبلی Modern Toolkit جور کنید. واحد کانتینر برای ویجت‌های قابل‌استفادهٔ مجدد عالی است.

کانتینر در برابر مدیا — هر کدام چه کاری؟

📊 Container queries vs media queries

سؤالی که می‌پرسید ترجیح بدهید ابزار رایج
عرض viewport مرورگر چقدر است؟ پوستهٔ صفحه، ناوبری، چندستون کل صفحه @media (min-width: …)
عرض همین والد دور کامپوننت چقدر است؟ کارت، ویجت، امبد در جاهای نابرابر بعد از container-type، @container (min-width: …)
هر دو لازم است؟ خیلی وقت‌ها بله MQ برای صفحه؛ CQ برای کامپوننت داخل اسلات

دو اسلات، یک کامپوننت

یک اسکچ کوچک نشان می‌دهد سود کار کجاست — دو کانتینر، یک کلاس کارت:

Sidebar rail and main stage share one card

css
.page {
display: flex;
gap: 1rem;
align-items: start;
}

.rail {
container-type: inline-size;
container-name: rail;
width: 16rem;
}

.stage {
container-type: inline-size;
container-name: stage;
flex: 1;
min-width: 0;
}

/* Same .product-card class in both slots — @container rules above decide layout */

لازم نیست فقط برای عرض اسلات، .product-card--sidebar و .product-card--main جدا بسازید. اسلات اندازه‌اش را می‌گوید؛ کارت گوش می‌دهد.

مدیای صفحه را با کانتینر کامپوننت جفت کنید

کوئری viewport را برای تصمیم‌های صفحه نگه دارید (جمع شدن ناوبری سایت، تک‌ستونه شدن کل پوسته). کوئری کانتینر را برای تصمیم‌های کامپوننت داخل هر اسلاتی که صفحه داده بگذارید:

Viewport for the page, container for the card

css
@media (max-width: 40rem) {
.page {
flex-direction: column;
}

.rail {
width: auto;
}
}

@container (min-width: 28rem) {
.product-card {
grid-template-columns: 10rem 1fr;
}
}

روی گوشی کوچک صفحه ستون می‌شود؛ روی دسکتاپ پهن ریل ممکن است هنوز باریک باشد و استیج پهن — فقط کوئری کانتینر این شکاف را تمیز بیان می‌کند.

خودتان امتحان کنید

  1. روی یک wrapper دور کارت container-type: inline-size بگذارید؛ در DevTools ببینید زمینهٔ containment ساخته شده.
  2. با @container (min-width: 24rem) کارت را از حالت پشته به دو ستون ببرید.
  3. container-name: panel بگذارید و با @container panel (min-width: 30rem) دوباره هدف بگیرید.
  4. عنوان را با cqi اندازه دهید و فقط عرض والد را عوض کنید (نه لزوماً پنجره) تا تایپ حرکت کند.
  5. یک @media برای پوستهٔ صفحه نگه دارید؛ همان منطق را داخل کارت تکرار نکنید.

اشتباه‌های رایج

  • نوشتن @container بدون container-type روی جد — چیزی برای اندازه گرفتن نیست
  • جایگزینی همهٔ مدیا کوئری‌ها با کوئری کانتینر — پوستهٔ صفحه هنوز مال @media است
  • سه کانتینر تو در تو و سردرگمی که کدام عرض برد — اسم بدهید و صریح هدف بگیرید
  • کپی کورکورانهٔ breakpointهای viewport (مثل 48rem) داخل هر ویجت — با اسلات هماهنگ کنید، نه با کاتالوگ دستگاه
  • قاطی کردن nesting (سلکتور و &) با containment — nesting فایل را مرتب می‌کند؛ کوئری کانتینر جعبه را اندازه می‌گیرد

جمع‌بندی

  • کوئری کانتینر از اندازهٔ والد استایل می‌دهد، نه فقط از viewport
  • container-type (اغلب inline-size)؛ در صورت نیاز container-name
  • با @container (min-width: …) یا @container name (…) نوادگان را بازآرایی کنید
  • وقتی طول باید از کانتینر پیروی کند سراغ cqi / cqw بروید
  • بعدی در Modern Toolkit: feature queries (@supports) — استایل را به قابلیت مرورگر گره بزنید

🧠 دانش خود را بیازمایید

آماده شروع

دانش خود را بیازمایید

خود را با این آزمون تعاملی به چالش بکشید و ببینید موضوع را چقدر خوب درک کرده‌اید

❓
6
سوالات
🎯
70%
برای قبولی
♾️
∞
زمان
🔄
∞
تلاش‌ها

📝 دستورالعمل‌ها

  • هر سوال را با دقت بخوانید
  • بهترین پاسخ را برای هر سوال انتخاب کنید
  • می‌توانید آزمون را هر چند بار که می‌خواهید تکرار کنید
  • پیشرفت شما در بالا نمایش داده می‌شود