کوئری کانتینر در CSS
Nesting سلکتورها را کنار هم نگه داشت. مدیا کوئری هنوز به viewport نگاه میکند. کوئری کانتینر سؤال دیگری میپرسد: عرضِ همین جعبهٔ والد چقدر است؟ همان کارت محصول در ریل باریک جمعوجور میماند و در ستون اصلی باز میشود — حتی اگر پنجرهٔ مرورگر عوض نشده باشد.
چرا viewport کافی نیست
در خیلی از صفحهها یک کامپوننت در جاهای نابرابر مینشیند: ریل کناری ۱۶rem و ناحیهٔ اصلیِ منعطف. هر دو جایگاهی یک عرض viewport دارند؛ پس @media (min-width: …) برای هر دو یکجور روشن میشود. باید استایل از کانتینری که دور کارت است بیاید، نه از کل صفحه.
زمینهٔ اندازهگیری بسازید
والدی را که باید اندازهاش گزارش شود انتخاب کنید. container-type را بگذارید — معمولاً inline-size تا بتوانید اندازهٔ اینلاین والد را بپرسید (در نوشتن افقی همان عرض) بدون اینکه حتماً هر دو محور را قفل کنید:
.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 {
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 بنویسید:
@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):
.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 برای کامپوننت داخل اسلات |
دو اسلات، یک کامپوننت
یک اسکچ کوچک نشان میدهد سود کار کجاست — دو کانتینر، یک کلاس کارت:
.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 را برای تصمیمهای صفحه نگه دارید (جمع شدن ناوبری سایت، تکستونه شدن کل پوسته). کوئری کانتینر را برای تصمیمهای کامپوننت داخل هر اسلاتی که صفحه داده بگذارید:
@media (max-width: 40rem) {
.page {
flex-direction: column;
}
.rail {
width: auto;
}
}
@container (min-width: 28rem) {
.product-card {
grid-template-columns: 10rem 1fr;
}
}
روی گوشی کوچک صفحه ستون میشود؛ روی دسکتاپ پهن ریل ممکن است هنوز باریک باشد و استیج پهن — فقط کوئری کانتینر این شکاف را تمیز بیان میکند.
خودتان امتحان کنید
- روی یک wrapper دور کارت
container-type: inline-sizeبگذارید؛ در DevTools ببینید زمینهٔ containment ساخته شده. - با
@container (min-width: 24rem)کارت را از حالت پشته به دو ستون ببرید. container-name: panelبگذارید و با@container panel (min-width: 30rem)دوباره هدف بگیرید.- عنوان را با
cqiاندازه دهید و فقط عرض والد را عوض کنید (نه لزوماً پنجره) تا تایپ حرکت کند. - یک
@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) — استایل را به قابلیت مرورگر گره بزنید
🧠 دانش خود را بیازمایید
دانش خود را بیازمایید
خود را با این آزمون تعاملی به چالش بکشید و ببینید موضوع را چقدر خوب درک کردهاید
📝 دستورالعملها
- هر سوال را با دقت بخوانید
- بهترین پاسخ را برای هر سوال انتخاب کنید
- میتوانید آزمون را هر چند بار که میخواهید تکرار کنید
- پیشرفت شما در بالا نمایش داده میشود