EduFlow
إتقان CSS الحديثة
⁦0%⁩

الوحدة 2 · تخطيط يصمد

الـ Container Queries

20 دقراءة 4 دبيئة تجريب الكود

الدرس في لمحة

اجعل بطاقة الجلسة تغيّر تخطيطها بحسب عرض الخانة التي تجلس فيها، باستخدام container queries للحجم ووحدات الحاوية واستعلامات النمط على الـ custom properties.

  1. 1أنشئ حاوية ثم استعلم عنها
  2. 2القاعدتان اللتان يتعثّر بهما الجميع
  3. 3وحدات الحاوية
  4. 4استعلامات النمط للأشكال المختلفة (variants)
  5. 5دورك الآن

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

تستخدم Waypoint بطاقة الجلسة نفسها في ثلاثة أماكن: شبكة الجدول الرئيسية، وشريط جانبي ضيّق بعنوان «Up next»، وواجهة عريضة بكامل العرض للـ keynote. الـ media query لا تستطيع إلا أن تسأل «ما عرض الشاشة؟»، والشاشة بالعرض نفسه في الحالات الثلاث. فحصلت البطاقة في الشريط الجانبي على التخطيط العريض، مضغوطًا في 280px، إلى أن أضاف أحدهم تجاوزًا .sidebar .session-card، ثم تجاوزًا .hero .session-card، وهكذا.

لا ينبغي أن تهتم البطاقة بمكانها. ينبغي أن تهتم بالمساحة المتاحة لها. والـ container queries (استعلامات الحاوية) تتيح لها أن تسأل عن ذلك بالضبط.

أنشئ حاوية ثم استعلم عنها

خطوتان. الأولى أن تعلن أيّ عنصر هو الحاوية، أي الخانة التي تجلس فيها البطاقة:

slots.css
.slot {
  container: session / inline-size;
}

هذا الاختصار يضبط container-name: session وcontainer-type: inline-size. النوع يخبر المتصفّح أنك ستستعلم عن الحجم الأفقي (inline size) لهذا العنصر، أي عرضه في الكتابة الأفقية، لذا يجب أن يستطيع حساب هذا العرض دون النظر إلى المحتوى بداخله.

والثانية أن تكتب تخطيط البطاقة على شكل استعلام عن تلك الحاوية:

session-card.css
.session-card {
  display: block;
}

@container session (width >= 400px) {
  .session-card {
    display: grid;
    grid-template-columns: 6rem 1fr;
    gap: 1rem;
  }
}

الآن تتراصّ البطاقة عموديًا في الشريط الجانبي بعرض 280px، وتنتقل إلى عمودين في الشبكة بعرض 640px، دون أن تعرف شيئًا عن أيٍّ منهما. الاسم اختياري؛ و@container (width >= 400px) بلا اسم تستخدم أقرب سلف له نوع حاوية حجم. والأسماء تفيد حين تتداخل الحاويات وتريد تخطّي إحداها.

نافذة متصفّح فيها خانة جانبية ضيّقة وخانة رئيسية عريضة. البطاقة في الخانة الضيّقة متراصّة: الوقت فوق العنوان. والبطاقة في الخانة العريضة جنبًا إلى جنب: عمود الوقت بجوار العنوان. الـ viewport: نفسه للاثنتين .slot 280px 09:30 العنوان .slot 640px 09:30 العنوان
البطاقة نفسها في خانتين: الاستعلام يقيس الخانة لا الـ viewport

القاعدتان اللتان يتعثّر بهما الجميع

لا يستطيع العنصر أن يستعلم عن نفسه. الاستعلام يبحث عن حاوية بين الأسلاف، لذا فإن container-type على .session-card مع @container { .session-card { … } } لا تفعل شيئًا للبطاقة نفسها. ضع الحاوية على غلاف.

الاحتواء يغيّر طريقة تحديد حجم الحاوية. احتواء inline-size يعني أن عرض الحاوية لا يمكن أن يعتمد على أبنائها؛ وإلا لاستطاع الاستعلام أن يغيّر المحتوى، فيتغيّر العرض، فيتغيّر الاستعلام، إلى ما لا نهاية.

وحدات الحاوية

داخل الحاوية تحصل على وحدات نسبية إليها: cqi تساوي 1% من الحجم الأفقي للحاوية، وcqb تساوي 1% من حجمها الرأسي (block size)، وcqmin/cqmax الأصغر أو الأكبر بينهما. إنها تجعل الـ component يتدرّج بسلاسة، لا عند نقاط التحوّل فقط:

CSS
.session-card h3 {
  font-size: clamp(1rem, 0.75rem + 2cqi, 1.5rem);
}

في الشريط الجانبي بعرض 280px يبقى العنوان قرب 1rem؛ وفي خانة بعرض 640px يكبر نحو 1.5rem. وإن لم يكن أيّ سلف حاوية حجم، ترجع وحدات الحاوية إلى وحدات الـ viewport الصغيرة، فلا تنكسر أبدًا.

استعلامات النمط للأشكال المختلفة (variants)

الحجم ليس الشيء الوحيد الذي قد تستجيب له البطاقة. بطاقة الـ keynote في الواجهة الرئيسية variant (شكل مختلف)، واستعلامات نمط الحاوية تتيح للعنصر الأب أن يعلن ذلك عبر custom property:

CSS
.hero { --variant: featured; }

@container style(--variant: featured) {
  .session-card {
    border-inline-start: 6px solid #6d28d9;
  }
}

لا تحتاج إلى container-type هنا: كل عنصر حاوية نمط افتراضيًا، فيفحص الاستعلام قيمة --variant المحسوبة على أقرب سلف. واستعلامات النمط تعمل اليوم مع الـ custom properties فقط؛ أما الاستعلام عن الخصائص العادية مثل style(display: grid) فغير مدعوم في أيّ مكان بعد.

دورك الآن

في التمرين تستخدم البطاقة media query، فتحصل على التخطيط الخاطئ في خانة واحدة على الأقل. حوّل .slot إلى حاوية مسمّاة، وانقل التخطيط إلى container query عند 400px، وأضف استعلام نمط للشكل المميّز. تغيّر الفحوصات عرض الخانة وتضبط --variant عليها لترى استجابة البطاقة. وبهذا يُغلق قسم التخطيط؛ وبعده ستجعل الخطوط والمسافات تتدرّج بمرونة عبر كل أحجام الخانات هذه.

أهم النقاط

  • container-type: inline-size تحوّل العنصر إلى حاوية (container)، و@container (width >= 400px) تنسّق العناصر داخله بحسب عرض ذلك العنصر، لا عرض الـ viewport.
  • لا يستطيع العنصر أن يستعلم عن نفسه؛ ضع container-type على غلاف واكتب الاستعلام للعناصر التي بداخله.
  • احتواء الحجم الأفقي (inline-size containment) يعني أن عرض الحاوية لا يمكن أن يأتي من محتواها، لذا تنهار الحاوية الموضوعة في سياق يتقلّص على محتواه ما لم يعطها شيءٌ ما عرضًا.
  • وحدات الحاوية مثل cqi (1% من الحجم الأفقي للحاوية) تتيح للخطوط والمسافات أن تتدرّج مع الـ component.
  • استعلامات النمط على الـ custom properties، مثل @container style(--variant: featured)، دخلت Baseline في مايو 2026؛ أما استعلامات الحجم فضمن Baseline منذ 2023.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

لماذا لا تنطبق هذه القاعدة أبدًا؟

CSS
.session-card { container-type: inline-size; }
@container (width >= 400px) {
  .session-card { display: grid; }
}
السؤال 2 من 4

وضعت container-type: inline-size على عنصر flex بلا عرض مضبوط، فانهار إلى عرض صفر. لماذا؟

السؤال 3 من 4

لعنوان بطاقة font-size: clamp(1rem, 4cqi, 1.5rem). إلامَ تشير 4cqi؟

السؤال 4 من 4

أيّ استعلام يطبّق الأنماط حين يضبط العنصر الأب --variant: featured؟

تدريب

بيئة تجريب الكود

دع البطاقة تقيس خانتها

تنتقل البطاقة إلى عمودين باستخدام media query، فتقيس الشاشة بدل خانتها. تضبط الفحوصات عرض .slot بين 300px و500px.

  1. اجعل .slot حاوية حجم اسمها session تتتبّع حجمها الأفقي (inline size).
  2. استبدل الـ media query بـ container query: حين تكون حاوية session بعرض 400px أو أكثر، تصبح البطاقة شبكة من عمودين؛ وتحت ذلك تبقى متراصّة.
  3. أضف استعلام نمط: حين تكون --variant بقيمة featured، يصبح حدّ البطاقة في جهة البداية (inline-start) بلون #6d28d9.
<div class="slot">
  <article class="session-card">
    <p class="time">09:30</p>
    <div class="body">
      <h3>Container Queries in Production</h3>
      <p>Cards that adapt to the slot they're in, not the screen.</p>
    </div>
  </article>
</div>جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

المعاينة

الـ console

(لا مخرجات)

الفحوص

  • الخانة حاوية inline-size اسمها session
  • عند 500px يقع الوقت بجوار المحتوى
  • عند 300px تتراصّ البطاقة
  • يحدث التبديل عند 400px بالضبط
  • –variant: featured تجعل الحدّ بنفسجيًا