{"id":"l-css-2-2","courseId":"css-mastery","lang":"ar","kind":"lesson","summary":"خطّط صفحة باستخدام grid-template-areas المسمّاة، وابنِ شبكة متحدّثين تختار عدد أعمدتها بنفسها باستخدام repeat(auto-fit, minmax()).","html":"<p>يخطّط flexbox الأشياء في اتجاه واحد ويترك لكل سطر أن يتّخذ قراراته بنفسه. هذا مثالي لصف من الفلاتر، وخاطئ لشبكة المتحدّثين في Waypoint، حيث يجب أن تصطفّ كل بطاقة في العمود مع البطاقات فوقها وتحتها. حين تحتاج إلى أن تتّفق الصفوف <em>والأعمدة</em> معًا، فأنت تريد grid.</p>\n<p>يبني هذا الدرس تخطيطين في صفحة الجدول: هيكل الصفحة بمناطق مسمّاة، وشبكة المتحدّثين التي تقرّر عدد أعمدتها بنفسها.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">ارسم الصفحة بقوالب المناطق</h2>\n<p>لصفحة الجدول رأس يمتدّ في الأعلى، وشريط جانبي للفلاتر، والمحتوى الرئيسي. باستخدام <code dir=\"ltr\">grid-template-areas</code> ترسم هذا التخطيط مباشرةً:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">layout.css</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.page</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  grid-template-columns</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">14</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> minmax</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">fr</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  grid-template-areas</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"header  header\"</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"filters main\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  gap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1.5</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.site-header</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid-area</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: header; }</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.filters</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">     { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid-area</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: filters; }</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.schedule</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid-area</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: main; }</span></span></code></pre></div>\n<p>كل سلسلة نصية صفّ، وكل كلمة داخلها عمود. تكرار الاسم (<code dir=\"ltr\">header header</code>) يجعل تلك المنطقة تمتدّ على العمودين. والنقطة <code dir=\"ltr\">.</code> تشير إلى خلية فارغة. ويجب أن تكون المناطق مستطيلة: الشكل على هيئة حرف L غير صالح، ويُسقَط التصريح كله.</p>\n<p>العائد يأتي حين يتغيّر التخطيط. على الشاشات الضيّقة يجب أن تجلس الفلاتر فوق الجلسات، فتعيد رسم السلاسل بدل نقل الـ HTML:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">@media</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">width</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> &#x3C;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 48</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  .page</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    grid-template-columns</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">minmax</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">fr</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    grid-template-areas</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">      \"header\"</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">      \"filters\"</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">      \"main\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>إعادة الترتيب بصريًا لا في الـ DOM</span></p>\n<p>تستطيع مناطق grid أن تضع العناصر بأيّ ترتيب بصري، لكن الـ focus من لوحة المفاتيح وقارئات الشاشة (screen readers) تتبع ترتيب الـ DOM. إن وضعت الفلاتر بصريًا <em>بعد</em> الجلسات بينما هي أولًا في الـ HTML، يتنقّل مستخدم لوحة المفاتيح بقفزات تبدو بلا منطق. أبقِ ترتيب المصدر منطقيًا، واستخدم المناطق لتعديل التخطيط لا المعنى.</p>\n</aside>\n<h2 id=\"sec-2\" tabindex=\"-1\">وحدة <code dir=\"ltr\">fr</code> وحدّها الأدنى الخفيّ</h2>\n<p>تقسّم <code dir=\"ltr\">fr</code> المساحة الحرّة في الشبكة بعد طرح الـ tracks الثابتة والفجوات. عمودان بقيمة <code dir=\"ltr\">1fr</code> في شبكة عرضها 600px مع فجوة 20px عرض كلٍّ منهما 290px.</p>\n<p>وهناك فخّ ستقابله عاجلًا أو آجلًا: <code dir=\"ltr\">1fr</code> اختصار لـ <code dir=\"ltr\">minmax(auto, 1fr)</code>، و<code dir=\"ltr\">auto</code> كحدّ أدنى تعني «على الأقل عرض المحتوى الأدنى (min-content)». ضع رابطًا طويلًا متصلًا أو كتلة كود في أحد العمودين فيتّسع ويسرق المساحة من الآخر. لهذا يستخدم هيكل الصفحة أعلاه <code dir=\"ltr\">minmax(0, 1fr)</code>: فهي تسمح للعمود الرئيسي بالتقلّص تحت حجم محتواه، ويُعالَج أيّ فيضان بداخله (بوضع <code dir=\"ltr\">overflow-x: auto</code> على كتلة الكود مثلًا). إنها نظير إصلاح <code dir=\"ltr\">min-width: 0</code> من الدرس السابق، لكن في grid.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">شبكة متحدّثين تعدّ أعمدتها بنفسها</h2>\n<p>في Waypoint 23 متحدّثًا. على الهاتف يجب أن يتكدّسوا عموديًا؛ وعلى الحاسوب المحمول أربعة أو خمسة في الصف. تصريح واحد يتعامل مع كل العروض:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">speakers.css</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.speakers</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  grid-template-columns</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">repeat</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">auto-fit</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">minmax</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">180</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">fr</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">));</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  gap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">16</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.speaker.featured</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  grid-column</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> / </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">-1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>اقرأها من الداخل إلى الخارج. <code dir=\"ltr\">minmax(180px, 1fr)</code> تقول إن كل عمود لا يقل عن 180px ولا يزيد على حصة متساوية من المساحة الحرّة. و<code dir=\"ltr\">repeat(auto-fit, …)</code> تطلب من المتصفّح أن ينشئ أكبر عدد ممكن من هذه الأعمدة يتّسع. في حاوية عرضها 640px بفجوات 16px، تتّسع ثلاثة أعمدة بعرض 180px (ثلاثة أعمدة وفجوتان تساوي 572px) ولا تتّسع أربعة، فتحصل على ثلاثة أعمدة يتمدّد كلٌّ منها إلى نحو 203px.</p>\n<p><code dir=\"ltr\">grid-column: 1 / -1</code> تجعل متحدّث الـ keynote يمتدّ من الخط الأول إلى الأخير، أيًّا كان عدد الأعمدة. أرقام الخطوط السالبة تُعدّ من نهاية الشبكة الصريحة.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 230\" role=\"img\" aria-labelledby=\"l-css-2-2-t1\"><defs><marker id=\"arrow-l-css-2-2-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-css-2-2-t1\">شبكتان بالعرض نفسه في كلٍّ منهما عنصران. مع auto-fill يشغل العنصران عمودين من أربعة أعمدة متساوية ويبقى اثنان من الـ tracks الفارغة المتقطّعة. ومع auto-fit تنطوي الـ tracks الفارغة ويأخذ كل عنصر نصف العرض.</title>\n  <text class=\"d-code\" x=\"20\" y=\"24\">auto-fill</text>\n  <rect class=\"d-box\" x=\"20\" y=\"36\" width=\"640\" height=\"64\" rx=\"8\"/>\n  <rect class=\"d-box-primary\" x=\"30\" y=\"46\" width=\"146\" height=\"44\" rx=\"6\"/>\n  <rect class=\"d-box-primary\" x=\"186\" y=\"46\" width=\"146\" height=\"44\" rx=\"6\"/>\n  <rect class=\"d-box d-dashed\" x=\"342\" y=\"46\" width=\"146\" height=\"44\" rx=\"6\"/>\n  <rect class=\"d-box d-dashed\" x=\"498\" y=\"46\" width=\"152\" height=\"44\" rx=\"6\"/>\n  <text class=\"d-label-muted\" x=\"380\" y=\"74\">فارغ</text>\n  <text class=\"d-label-muted\" x=\"540\" y=\"74\">فارغ</text>\n  <text class=\"d-code\" x=\"20\" y=\"138\">auto-fit</text>\n  <rect class=\"d-box\" x=\"20\" y=\"150\" width=\"640\" height=\"64\" rx=\"8\"/>\n  <rect class=\"d-box-primary\" x=\"30\" y=\"160\" width=\"306\" height=\"44\" rx=\"6\"/>\n  <rect class=\"d-box-primary\" x=\"344\" y=\"160\" width=\"306\" height=\"44\" rx=\"6\"/>\n</svg><figcaption>auto-fill تحتفظ بالـ tracks الفارغة، وauto-fit تطويها فتتمدّد العناصر</figcaption></figure>\n<p>الفرق بين <code dir=\"ltr\">auto-fit</code> و<code dir=\"ltr\">auto-fill</code> لا يظهر إلا حين تكون العناصر أقل من الأعمدة. <code dir=\"ltr\">auto-fill</code> تحتفظ بالـ tracks الفارغة، فيبقى المتحدّثان بحجم البطاقة ويتركان فراغًا. و<code dir=\"ltr\">auto-fit</code> تطوي الـ tracks الفارغة إلى الصفر، فيتمدّد المتحدّثان على امتداد الصف. ولشبكة متحدّثين تكاد تكون فارغة أحيانًا (اليوم الثاني فيه أربعة متحدّثين فقط)، اختر بحسب التصميم: <code dir=\"ltr\">auto-fill</code> لعرض بطاقات ثابت، و<code dir=\"ltr\">auto-fit</code> لصف ممتلئ.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>احمِ الحدّ الأدنى على الشاشات الصغيرة جدًا</span></p>\n<p>إن كانت الحاوية أضيق من 180px، تفيض <code dir=\"ltr\">minmax(180px, 1fr)</code>. كتابة <code dir=\"ltr\">minmax(min(180px, 100%), 1fr)</code> تحدّ الحدّ الأدنى بعرض الحاوية. سترى لماذا ينجح هذا في درس <a href=\"/ar/lesson/css-mastery/l-css-2-4\">التحجيم الذاتي</a>.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">دورك الآن</h2>\n<p>يعطيك التمرين هيكل الصفحة وشبكة المتحدّثين بأعمدة مكتوبة يدويًا. سمِّ المناطق، وحوّل المتحدّثين إلى <code dir=\"ltr\">auto-fit</code>، واجعل الـ keynote يمتدّ على الصف كاملًا. تغيّر الفحوصات حجم الصفحة لتتأكّد من أن عدد الأعمدة يتكيّف. وبعدها ستجعل <em>محتويات</em> بطاقات grid تصطفّ عبر البطاقات باستخدام الـ subgrid.</p>\n","toc":[{"id":"sec-1","text":"ارسم الصفحة بقوالب المناطق","level":2},{"id":"sec-2","text":"وحدة fr وحدّها الأدنى الخفيّ","level":2},{"id":"sec-3","text":"شبكة متحدّثين تعدّ أعمدتها بنفسها","level":2},{"id":"sec-4","text":"دورك الآن","level":2}],"takeaways":["تتيح لك <code dir=\"ltr\">grid-template-areas</code> أن ترسم التخطيط كأنه رسم بالحروف (ASCII art)، وإعادة ترتيب الصفحة لحجم شاشة آخر تعني إعادة رسم السلاسل النصية، لا نقل الـ HTML.","<code dir=\"ltr\">repeat(auto-fit, minmax(12rem, 1fr))</code> تنشئ أكبر عدد ممكن من الأعمدة التي تتّسع وتمدّدها لتملأ الصف، دون media queries.","<code dir=\"ltr\">auto-fill</code> تحتفظ بالـ tracks (مسارات الشبكة) الفارغة حين تكون العناصر قليلة، بينما <code dir=\"ltr\">auto-fit</code> تطويها فتتمدّد العناصر لتملأ الصف.","لـ <code dir=\"ltr\">1fr</code> حدّ أدنى تلقائي يساوي حجم المحتوى؛ استخدم <code dir=\"ltr\">minmax(0, 1fr)</code> حين يجب السماح للـ track بالتقلّص تحت حجم محتواه."],"further":[{"title":"Grid template areas (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout/Grid_template_areas"},{"title":"repeat() (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/repeat"},{"title":"Grid (web.dev Learn CSS)","url":"https://web.dev/learn/css/grid"}],"quiz":[{"q":"<p>شبكة متحدّثين تستخدم <code dir=\"ltr\">repeat(auto-fill, minmax(180px, 1fr))</code> في حاوية عرضها 900px، لكن فيها متحدّثان فقط. ماذا ترى؟</p>","options":[{"text":"بطاقتين عريضتين تتقاسمان الـ 900px كاملة.","why":"هذا سلوك <code dir=\"ltr\">auto-fit</code>، التي تطوي الـ tracks الفارغة. أما <code dir=\"ltr\">auto-fill</code> فتحتفظ بها."},{"text":"بطاقتين بعرض يقارب 180px، والـ tracks الفارغة ما زالت تشغل بقية الصف.","why":"صحيح. <code dir=\"ltr\">auto-fill</code> تنشئ أكبر عدد من الـ tracks يتّسع (خمسة هنا) سواء وُجدت عناصر لها أم لا، فتجلس البطاقتان في أول عمودين من خمسة أعمدة متساوية."},{"text":"بطاقتين بعرض 180px بالضبط، محاذاتين للبداية، دون tracks إضافية.","why":"عرض البطاقتين قريب من ذلك فعلًا، لكن ليس لغياب الـ tracks الإضافية. هناك ثلاثة tracks فارغة موجودة وتحجز المساحة، وهذا بالضبط ما يُبقي البطاقتين ضيّقتين."}],"answer":1},{"q":"<p>ما الذي يضعه هذا التخطيط في الصف الثاني، العمود الأول؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.page</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  grid-template-columns</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">14</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">fr</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  grid-template-areas</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"header header\"</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"filters main\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","options":[{"text":"العنصر الذي له <code dir=\"ltr\">grid-area: header</code>.","why":"منطقة header تغطّي عمودي الصف الأول فقط."},{"text":"لا شيء؛ يجب أن تكون المناطق مستطيلة، لذا هذا غير صالح.","why":"كلتا المنطقتين هنا مستطيلتان (header بحجم 1×2، وfilters وmain بحجم 1×1)، لذا القالب صالح."},{"text":"العنصر الذي له <code dir=\"ltr\">grid-area: filters</code>.","why":"صحيح. كل سلسلة صفّ وكل كلمة عمود، لذا فالعمود الأول في الصف الثاني هو <code dir=\"ltr\">filters</code>."}],"answer":2},{"q":"<p>شبكة لها <code dir=\"ltr\">grid-template-columns: 1fr 1fr</code> وُضعت في عمودها الأول كتلة كود فيها سطر طويل جدًا، فأصبح العمودان غير متساويين. ما الإصلاح؟</p>","options":[{"text":"<code dir=\"ltr\">grid-template-columns: minmax(0, 1fr) minmax(0, 1fr)</code>","why":"صحيح. لـ <code dir=\"ltr\">1fr</code> المجرّدة حدّ أدنى تلقائي يساوي حجم المحتوى الأدنى (min-content)؛ و<code dir=\"ltr\">minmax(0, 1fr)</code> تزيل هذا الحدّ فيبقى العمودان متساويين."},{"text":"<code dir=\"ltr\">grid-template-columns: 50% 50%</code>","why":"النسب المئوية تتجاهل الفجوة، فمع أيّ <code dir=\"ltr\">gap</code> تفيض الشبكة خارج حاويتها."},{"text":"<code dir=\"ltr\">grid-auto-flow: dense</code>","why":"<code dir=\"ltr\">dense</code> تغيّر طريقة وضع العناصر في الفراغات؛ ولا تؤثّر في أحجام الـ tracks."},{"text":"<code dir=\"ltr\">justify-items: stretch</code>","why":"هذه هي القيمة الافتراضية أصلًا، ولا تؤثّر إلا في كيفية ملء العناصر لخلاياها، لا في عرض الـ tracks."}],"answer":0}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<div class=\"page\">\n  <header class=\"site-header\">Waypoint Conf 2026</header>\n  <nav class=\"filters\">Tracks</nav>\n  <main class=\"speakers\">\n    <div class=\"speaker featured\">Keynote · Ana Ortiz</div>\n    <div class=\"speaker\">Kenji Watanabe</div>\n    <div class=\"speaker\">Layla Haddad</div>\n    <div class=\"speaker\">Tom Becker</div>\n    <div class=\"speaker\">Priya Nair</div>\n    <div class=\"speaker\">Marcus Lee</div>\n  </main>\n</div>","css":".page {\n  width: 860px; /* fixed for this exercise */\n  display: grid;\n  gap: 20px;\n}\n.site-header, .filters, .speaker {\n  padding: 12px;\n  border-radius: 10px;\n  background: #f5f3ff;\n}\n.page {\n  grid-template-columns: 200px minmax(0, 1fr);\n}\n\n.speakers {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 16px;\n}\n"},"solution":{"html":"<div class=\"page\">\n  <header class=\"site-header\">Waypoint Conf 2026</header>\n  <nav class=\"filters\">Tracks</nav>\n  <main class=\"speakers\">\n    <div class=\"speaker featured\">Keynote · Ana Ortiz</div>\n    <div class=\"speaker\">Kenji Watanabe</div>\n    <div class=\"speaker\">Layla Haddad</div>\n    <div class=\"speaker\">Tom Becker</div>\n    <div class=\"speaker\">Priya Nair</div>\n    <div class=\"speaker\">Marcus Lee</div>\n  </main>\n</div>","css":".page {\n  width: 860px; /* fixed for this exercise */\n  display: grid;\n  gap: 20px;\n}\n.site-header, .filters, .speaker {\n  padding: 12px;\n  border-radius: 10px;\n  background: #f5f3ff;\n}\n.page {\n  grid-template-columns: 200px minmax(0, 1fr);\n  grid-template-areas:\n    \"header  header\"\n    \"filters main\";\n}\n.site-header { grid-area: header; }\n.filters { grid-area: filters; }\n.speakers { grid-area: main; }\n\n.speakers {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n  gap: 16px;\n}\n.speaker.featured {\n  grid-column: 1 / -1;\n}\n"},"checks":[{"id":"uses-areas","test":"return style('.page', 'grid-template-areas') !== 'none';"},{"id":"header-spans","test":"const box = (s) => (typeof s === 'string' ? $(s) : s).getBoundingClientRect(); const cols = () => new Set($$('.speaker:not(.featured)').filter((el) => style(el, 'display') !== 'none').map((el) => Math.round(box(el).left))).size; const h = box('.site-header'), f = box('.filters'), m = box('.speakers'); return Math.abs(h.width - 860) < 1 && f.top >= h.bottom && m.top >= h.bottom && f.right <= m.left;"},{"id":"three-columns","test":"const box = (s) => (typeof s === 'string' ? $(s) : s).getBoundingClientRect(); const cols = () => new Set($$('.speaker:not(.featured)').filter((el) => style(el, 'display') !== 'none').map((el) => Math.round(box(el).left))).size; return cols() === 3;"},{"id":"featured-spans","test":"const box = (s) => (typeof s === 'string' ? $(s) : s).getBoundingClientRect(); const cols = () => new Set($$('.speaker:not(.featured)').filter((el) => style(el, 'display') !== 'none').map((el) => Math.round(box(el).left))).size; return Math.abs(box('.speaker.featured').width - box('.speakers').width) < 1;"},{"id":"narrow-two-columns","test":"const box = (s) => (typeof s === 'string' ? $(s) : s).getBoundingClientRect(); const cols = () => new Set($$('.speaker:not(.featured)').filter((el) => style(el, 'display') !== 'none').map((el) => Math.round(box(el).left))).size; const page = $('.page'); page.style.width = '620px'; await tick(16); const n = cols(); page.style.width = ''; await tick(16); return n === 2;"},{"id":"few-items-stretch","test":"const box = (s) => (typeof s === 'string' ? $(s) : s).getBoundingClientRect(); const cols = () => new Set($$('.speaker:not(.featured)').filter((el) => style(el, 'display') !== 'none').map((el) => Math.round(box(el).left))).size; const hide = $$('.speaker').slice(0, 4); hide.forEach((el) => (el.style.display = 'none')); await tick(16); const w = box($$('.speaker')[4]).width; const main = box('.speakers').width; hide.forEach((el) => (el.style.display = '')); await tick(16); return Math.abs(w - (main - 16) / 2) < 1.5;"}],"title":"سمِّ المناطق ودع المتحدّثين يتدفّقون","prompt":"<p>عرض الصفحة ثابت عند 860px في هذا التمرين.</p>\n<ol>\n<li>أعطِ <code dir=\"ltr\">.page</code> تخطيطًا بـ <code dir=\"ltr\">grid-template-areas</code>: <code dir=\"ltr\">header</code> على العمودين في الصف الأول، ثم <code dir=\"ltr\">filters</code> و<code dir=\"ltr\">main</code> جنبًا إلى جنب. وزّع <code dir=\"ltr\">.site-header</code> و<code dir=\"ltr\">.filters</code> و<code dir=\"ltr\">.speakers</code> على تلك المناطق.</li>\n<li>استبدل <code dir=\"ltr\">repeat(3, 1fr)</code> الثابتة في المتحدّثين بأعمدة <strong>لا يقل عرضها عن 180px</strong>، بأكبر عدد يتّسع، و<strong>تتمدّد لتملأ الصف</strong> حين يكون المتحدّثون قليلين.</li>\n<li>اجعل المتحدّث <code dir=\"ltr\">.featured</code> يمتدّ على الصف كاملًا.</li>\n</ol>\n<p>تغيّر الفحوصات حجم الصفحة وتخفي بعض المتحدّثين لترى كيف تتفاعل شبكتك.</p>\n","hints":["كل سلسلة في <code dir=\"ltr\">grid-template-areas</code> صفّ واحد؛ كرّر الاسم ليمتدّ على عدّة أعمدة.","للمتحدّثين تريد <code dir=\"ltr\">repeat()</code> بكلمة مفتاحية تطوي الـ tracks الفارغة، و<code dir=\"ltr\">minmax()</code> بحدّ أدنى 180px.","<code dir=\"ltr\">grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));</code> و<code dir=\"ltr\">.speaker.featured { grid-column: 1 / -1; }</code>."],"explanation":"<p>تصف <code dir=\"ltr\">grid-template-areas</code> التخطيط على شكل صفوف من الأسماء؛ <code dir=\"ltr\">header header</code> تمتدّ على العمودين و<code dir=\"ltr\">filters main</code> تضع الاثنين جنبًا إلى جنب، و<code dir=\"ltr\">grid-area</code> تُسقط كل عنصر في مكانه. وللمتحدّثين تضبط <code dir=\"ltr\">minmax(180px, 1fr)</code> مدى كل عمود، و<code dir=\"ltr\">repeat(auto-fit, …)</code> تنشئ أكبر عدد يتّسع: ثلاثة في العمود الرئيسي بعرض 640px، واثنان حين تضيق الصفحة. ومع متحدّثَين ظاهرين فقط، تطوي <code dir=\"ltr\">auto-fit</code> الـ tracks الفارغة فتتمدّد البطاقتان إلى نصف الصف لكلٍّ منهما؛ أما <code dir=\"ltr\">auto-fill</code> فكانت ستتركهما ضيّقتين. و<code dir=\"ltr\">grid-column: 1 / -1</code> تمدّ الـ keynote من أول خط في الشبكة إلى آخره، أيًّا كان عدد الأعمدة.</p>\n","checkLabels":{"uses-areas":"الصفحة تستخدم grid-template-areas","header-spans":"الرأس يمتدّ في الأعلى، والفلاتر على يسار المتحدّثين","three-columns":"المتحدّثون يشكّلون ثلاثة أعمدة عند هذا العرض","featured-spans":"المتحدّث المميّز يمتدّ على الصف كاملًا","narrow-two-columns":"الصفحة الأضيق تحصل على عمودين","few-items-stretch":"مع متحدّثَين فقط، يتمدّدان ليملآ الصف"}},"words":586,"readMinutes":3}