Container Queries در CSS به شما اجازه می‌دهد ظاهر یک کامپوننت را بر اساس اندازه ظرف (کانتینر) نزدیکش تغییر دهید، نه بر اساس عرض کل صفحه. برای استفاده: روی والد منطقی کامپوننت container-type را فعال کنید و با @container قوانین واکنش‌گرا بنویسید. نتیجه این است که همان کامپوننت در سایدبار باریک و محتوای تمام‌عرض، بدون هک و کلاس‌های اضافی، به‌درستی رفتار می‌کند.

Container Queries دقیقا چه مسئله‌ای را حل می‌کند؟

مشکل Media Query این است که فقط به اندازه ویوپورت نگاه می‌کند. اما بسیاری از تصمیم‌های طراحی باید محلی باشند: یک کارت محصول داخل سایدبار نباید مثل همان کارت در بخش قهرمان (Hero) نمایش داده شود. Container Query اندازه کانتینر واقعی کارت را می‌سنجد و بر اساس آن چیدمان، تایپوگرافی و ترازبندی را تغییر می‌دهد.

پیش‌نیاز و سازگاری

این قابلیت در مرورگرهای مدرن پشتیبانی می‌شود. اگر نیاز به اطمینان دارید، با یک @supports ساده مسیر ارتقا تدریجی بسازید:

/* استایل پایه برای همه مرورگرها */
.card__content { display:block; }

/* اگر Container Queries پشتیبانی شود */
@supports (container-type: inline-size) {
  /* استایل‌های پیشرفته مبتنی بر کانتینر */
}

نکته: container-type دو مقدار مهم دارد. inline-size فقط محور افقی (در جهت نوشتار) را جدا می‌کند و رایج‌ترین انتخاب است. size هر دو محور را جدا می‌کند و هزینه محاسباتی بیشتری دارد؛ مگر نیاز خاص، inline-size را ترجیح دهید.

شروع سریع در سه گام

  1. کانتینر را علامت‌گذاری کنید: نزدیک‌ترین والد منطقی کامپوننت را به عنوان کانتینر تعریف کنید.

    <div class="card">
      <img class="card__media" src="..." alt="...">
      <div class="card__content">
        <h3 class="card__title">عنوان</h3>
        <p class="card__desc">توضیح کوتاه</p>
        <span class="card__price">450,000</span>
      </div>
    </div>
    .card { 
      container-type: inline-size; /* این عنصر، کانتینر می‌شود */
      padding: 1rem; border: 1px solid #ddd; border-radius: .75rem;
    }
    
  2. @container بنویسید: استایل‌های وابسته به اندازه کانتینر را تعریف کنید.

    /* حالت پایه: چیدمان ستونی */
    .card__content { display:block; }
    
    /* وقتی عرض کانتینر کارت به 28rem رسید، چیدمان را دو ستونه کن */
    @container (min-width: 28rem) {
      .card__content {
        display: grid;
        grid-template-columns: 160px 1fr;
        gap: 1rem;
        align-items: start;
      }
      .card__media { width: 160px; height: auto; border-radius: .5rem; }
      .card__price { justify-self: start; font-weight: 600; }
    }
    
  3. تست کنید: همان کارت را در سایدبار باریک و در محتوای تمام‌عرض قرار دهید. بدون نیاز به کلاس اضافی، کارت خودش را با ظرف هماهنگ می‌کند.

یک مثال عملی: کارت محصول با رفتار واقعا واکنش‌گرا

هدف: کارت محصول در کانتینر باریک عمودی بماند و در کانتینر پهن به چیدمان تصویری-متن تبدیل شود.

<aside class="sidebar">
  <div class="card">
    <img class="card__media" src="thumb.jpg" alt="محصول">
    <div class="card__content">
      <h3 class="card__title">هدفون بی‌سیم</h3>
      <p class="card__desc">باتری 30 ساعته، نویزکنسلینگ.</p>
      <span class="card__price">3,250,000 تومان</span>
      <button class="card__cta">افزودن به سبد</button>
    </div>
  </div>
</aside>

<main class="content">
  <div class="card">... همان ساختار ...</div>
</main>
.sidebar { width: 320px; }
.content { width: min(900px, 100%); margin-inline: auto; }

/* کانتینر را روی خود کارت فعال می‌کنیم */
.card { container-type: inline-size; }

/* پایه */
.card__media { width: 100%; height: auto; border-radius: .5rem; }
.card__title { margin: .5rem 0; font-size: 1rem; }
.card__desc { color: #555; font-size: .9rem; }
.card__price { display: inline-block; margin-top: .5rem; color: #222; }
.card__cta { display: inline-block; margin-top: .75rem; }

/* وقتی کارت جا دارد، به چیدمان دو ستونه برو */
@container (min-width: 34rem) {
  .card__content {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: 1rem 1.25rem;
  }
  .card__media { width: 220px; }
  .card__title { font-size: 1.125rem; }
  .card__cta { justify-self: start; }
}

بررسی نتیجه: عرض ویوپورت را تغییر ندهید؛ پهنای والد کارت را کم و زیاد کنید. می‌بینید که کارت مطابق ظرف خودش تغییر می‌کند.

واحدهای cqw/cqh/cqi/cqb و تایپوگرافی سیال مبتنی بر کانتینر

Container Query Units به شما اجازه می‌دهند اندازه‌ها را درصدی از کانتینر بگیرید، نه ویوپورت:

  • cqw: یک درصد از عرض کانتینر
  • cqh: یک درصد از ارتفاع کانتینر
  • cqi/cqb: یک درصد از اندازه در محور inline/block (سازگار با جهت نوشتار)
  • cqmin/cqmax: کوچک‌ترین/بزرگ‌ترین بین cqi و cqb
.card { container-type: inline-size; }

/* تیتر با رشد نرم نسبت به عرض کارت، اما محدود */
.card__title { font-size: clamp(1rem, 2.2cqi, 1.35rem); }

/* گرید با ستون اول معادل 30% عرض کانتینر */
@container (min-width: 36rem) {
  .card__content { grid-template-columns: 30cqw 1fr; }
}

این واحدها کمک می‌کنند بدون نوشتن چندین آستانه (breakpoint) رفتار سیال‌تری بسازید.

نام‌گذاری کانتینر و کوئری‌های تو در تو

وقتی چند کانتینر در سلسله‌مراتب دارید، نام‌گذاری ابهام را رفع می‌کند.

/* شِماهنگ: container: <name> / <type> */
.card { container: card / inline-size; }
.section { container: section / inline-size; }

/* قوانین فقط وقتی اندازه کانتینر card به حد مشخص برسد اعمال می‌شوند */
@container card (min-width: 40rem) {
  .card__content { grid-template-columns: 260px 1fr; }
}

می‌توانید داخل یک @container، بسته به کانتینر والد نزدیک، دوباره @container دیگری برای کانتینر نام‌دار بالاتر بنویسید؛ اما خوانایی را حفظ کنید و از وابستگی‌های پیچیده پرهیز کنید.

Style Queries (پیشرفته و اختیاری)

علاوه بر اندازه، می‌توانید بر اساس مقدار متغیرهای سفارشی روی کانتینر (CSS Custom Properties) استایل بدهید. این قابلیت برای الگوهای تم‌بندی محلی مفید است.

.card { 
  container-type: inline-size;
  --tone: light; /* می‌توانید روی کانتینر مقدار دهید */
}

@container style(--tone: dark) {
  .card { background: #111; color: #eee; }
}

در حال حاضر، تکیه روی متغیرهای سفارشی قابل اتکاتر است. برای ویژگی‌های استاندارد، پیش از اتکا در محصول، وضعیت پشتیبانی را بررسی کنید.

خطاهای رایج و چک‌لیست سریع

  • فراموشی container-type: بدون آن، @container هیچ اثری ندارد.
  • کانتینر اشتباه: کانتینری را انتخاب کنید که منطقی‌ترین محدوده تصمیم‌گیری برای کامپوننت باشد (معمولا ریشه خود کامپوننت). اگر باید خود ریشه تغییر چیدمان دهد، الگوی «inner wrapper» بسازید و آن را هدف قرار دهید.
  • استفاده عجولانه از size: اگر فقط به بعد افقی نیاز دارید، inline-size را انتخاب کنید تا از عوارض جداسازی کامل اندازه‌ها دور بمانید.
  • انتظار اثر روی خود کانتینر: قوانین داخل @container بر اساس نزدیک‌ترین کانتینرِ «نیا» اعمال می‌شوند. برای تغییر ریشه، سبک را به یک فرزند قابل کنترل (مثل .card__content) منتقل کنید.
  • تداخل با Media Query جهانی: نقش‌ها را تفکیک کنید؛ Media Query برای اسکلت‌بندی کلی صفحه و Container Query برای رفتار محلی کامپوننت.

الگوی پیشنهادی برای طراحی سیستماتیک

  1. در سطح صفحه: با Media Query فقط ستون‌بندی کلان (header, main, sidebar) را تنظیم کنید.
  2. در سطح کامپوننت: هر کامپوننت ریشه‌اش container-type داشته باشد و قوانین واکنش‌گرایی محلی‌اش را با @container بنویسید.
  3. تایپوگرافی و فضاها: از cqi/cqw با clamp استفاده کنید تا مقیاس‌ها نرم و کنترل‌شده رشد کنند.
/* اسکلت کلی با media query (نمونه) */
@media (min-width: 64rem) {
  .layout { display:grid; grid-template-columns: 280px 1fr; gap: 2rem; }
}

/* درون هر کارت: واکنش‌گرایی محلی با container query */
.card { container-type: inline-size; }
@container (min-width: 32rem) { .card__content { display:grid; grid-template-columns: 200px 1fr; } }

تست و دیباگ موثر

  • در DevTools، هنگام انتخاب یک عنصر زیرمجموعه، بخش Styles را ببینید: قوانین @container فعال/غیرفعال می‌شوند و شرط آنها نمایش داده می‌شود.
  • ابعاد کانتینر را در حین توسعه با یک outline موقتی ببینید:
[style*="container-type"], [container-type] { outline: 1px dashed #bbb; outline-offset: 2px; }
  • برای سنجش آستانه‌ها، به جای تغییر عرض صفحه، عرض والد را با یک کلاس کم‌عرض/پهن در محیط توسعه تغییر دهید تا رفتار محلی را سریع بررسی کنید.

چه زمانی همچنان به Media Query نیاز داریم؟

Media Query برای تصمیم‌های سراسری مناسب است: تغییر چینش هدر/فوتر، فعال کردن منوی همبرگری، یا جابجایی ناحیه‌های اصلی صفحه. Container Query برای تصمیم‌های محلی کامپوننت بهتر است: جابجایی تصویر و متن کارت، نمایش ترازبندی دکمه، یا کم و زیاد شدن فاصله‌ها. ترکیب این دو، کنترل کامل را به شما می‌دهد.

الگوی پیشرفته: کارت چندمرحله‌ای با نام کانتینر و واحدهای سیال

.card { 
  container: card / inline-size; 
  padding: clamp(.75rem, 1.5cqi, 1.25rem);
}

.card__title { font-size: clamp(1rem, 2.2cqi, 1.35rem); }
.card__desc  { font-size: clamp(.9rem, 1.8cqi, 1.05rem); line-height: 1.6; }

/* سه آستانه معنادار بر اساس ظرفیت واقعی کارت */
@container card (min-width: 28rem) {
  .card__content { display:grid; grid-template-columns: 160px 1fr; gap: 1rem; }
}
@container card (min-width: 36rem) {
  .card__content { grid-template-columns: 200px 1fr; }
}
@container card (min-width: 44rem) {
  .card__content { grid-template-columns: 240px 1fr; gap: 1.25rem; }
}

گام بعدی چیست؟

یک کامپوننت پرکاربرد از پروژه‌تان را انتخاب کنید (مثل کارت، باکس خبر یا آیتم لیست)، container-type را روی ریشه‌اش فعال کنید و فقط یک آستانه معنادار با @container اضافه کنید. پس از تجربه اولین بهبود، به تدریج آستانه‌ها و واحدهای cqi/cqw را اضافه کنید. با همین رویکرد افزایشی، سیستم طراحی شما واقعا واکنش‌گرا و قابل پیش‌بینی می‌شود.