{"id":"l-css-2-3","courseId":"css-mastery","lang":"ar","kind":"lesson","summary":"استخدم الـ subgrid لتصطفّ أجزاء كل بطاقة جلسة (الوقت والعنوان والملخّص والقاعة) عبر صف البطاقات كله، أيًّا كان طول كل عنوان.","html":"<p>ضع ثلاث بطاقات جلسات من Waypoint جنبًا إلى جنب، وستقفز المشكلة أمامك. عنوانٌ يتّسع في سطر، وآخر يلتفّ على سطرين، وثالث على ثلاثة. كل بطاقة تخطّط محتواها بنفسها، فتبدأ الملخّصات على ثلاثة ارتفاعات مختلفة، وتشكّل تسميات القاعات في الأسفل درجًا. المصمّمون يلاحظون. والمستخدمون يلاحظون أقل، لكن الصفحة تبدو غير مكتملة.</p>\n<p>الإصلاحات القديمة كانت ارتفاعات ثابتة (تنكسر مع المحتوى الحقيقي)، أو JavaScript يقيس كل عنوان. أما الـ subgrid (الشبكة الفرعية) فيجعل البطاقات تتشارك مجموعة صفوف واحدة.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">لماذا لا تصطفّ الشبكات المتداخلة</h2>\n<p>حين تصبح البطاقة <code dir=\"ltr\">display: grid</code>، تنشئ tracks خاصة بها ومستقلة. صف العنوان فيها بارتفاع عنوانها <em>هي</em>؛ وصف العنوان في البطاقة المجاورة بارتفاع <em>ذلك</em> العنوان. لا شيء يربط بينهما، لأن كل بطاقة لا تعرف إلا محتواها.</p>\n<p>ما تريده هو أن يكون «صف العنوان» track واحدًا تتشاركه كل البطاقات في الصف البصري نفسه، ويتحدّد حجمه بأطول عنوان. وهذا الـ track المشترك يجب أن يعيش في الأب، أي شبكة <code dir=\"ltr\">.sessions</code>، وعلى البطاقات أن تستعيره.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">استعارة صفوف الأب</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">sessions.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\">.sessions</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-fill</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\">min</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\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">100</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</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\">24</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>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</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-row</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: span </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;              </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* time, title, abstract, room */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  grid-template-rows</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">subgrid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* use the parent's four rows */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  row-gap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">8</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;                  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* tighter than the parent's 24px */</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>تصريحان يؤدّيان العمل. <code dir=\"ltr\">grid-row: span 4</code> تجعل كل بطاقة تشغل أربعة صفوف من الشبكة الأب. و<code dir=\"ltr\">grid-template-rows: subgrid</code> تخبر البطاقة ألّا تنشئ صفوفها الخاصة بل تستخدم الصفوف الأربعة التي تمتدّ عليها. ويوضع أبناء البطاقة الأربعة (الوقت والعنوان والملخّص والقاعة) في صفوف الأب تلك بالترتيب.</p>\n<p>الآن يحدّد المتصفّح حجم كل صف في الأب بأطول محتوى وُضع فيه <em>من كل البطاقات في ذلك الصف</em>. يكبر track العنوان ليتّسع للعنوان ذي الأسطر الثلاثة، وتحصل العناوين الأقصر على الـ track نفسه، ويبدأ كل ملخّص على الخط نفسه. وتصطفّ تسميات القاعات في الأسفل.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 700 260\" role=\"img\" aria-labelledby=\"l-css-2-3-t1\"><defs><marker id=\"arrow-l-css-2-3-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-3-t1\">يسارًا: ثلاث بطاقات لكتل عناوينها ارتفاعات مختلفة، فتقع تسميات القاعات تحتها على ارتفاعات مختلفة. يمينًا: البطاقات الثلاث نفسها بخطوط صفوف مشتركة، فتتشارك العناوين صفًا طويلًا واحدًا وتصطفّ تسميات القاعات.</title>\n  <text class=\"d-label-strong\" x=\"20\" y=\"22\">صفوف خاصة</text>\n  <rect class=\"d-box\" x=\"20\" y=\"34\" width=\"96\" height=\"200\" rx=\"8\"/>\n  <rect class=\"d-box\" x=\"124\" y=\"34\" width=\"96\" height=\"200\" rx=\"8\"/>\n  <rect class=\"d-box\" x=\"228\" y=\"34\" width=\"96\" height=\"200\" rx=\"8\"/>\n  <rect class=\"d-box-primary\" x=\"28\" y=\"44\" width=\"80\" height=\"24\" rx=\"4\"/>\n  <rect class=\"d-box-primary\" x=\"132\" y=\"44\" width=\"80\" height=\"48\" rx=\"4\"/>\n  <rect class=\"d-box-primary\" x=\"236\" y=\"44\" width=\"80\" height=\"72\" rx=\"4\"/>\n  <rect class=\"d-box-accent\" x=\"28\" y=\"76\" width=\"80\" height=\"20\" rx=\"4\"/>\n  <rect class=\"d-box-accent\" x=\"132\" y=\"100\" width=\"80\" height=\"20\" rx=\"4\"/>\n  <rect class=\"d-box-accent\" x=\"236\" y=\"124\" width=\"80\" height=\"20\" rx=\"4\"/>\n  <text class=\"d-label-muted\" x=\"40\" y=\"252\">القاعات غير متحاذية</text>\n  <text class=\"d-label-strong\" x=\"380\" y=\"22\">صفوف subgrid</text>\n  <rect class=\"d-box\" x=\"380\" y=\"34\" width=\"96\" height=\"200\" rx=\"8\"/>\n  <rect class=\"d-box\" x=\"484\" y=\"34\" width=\"96\" height=\"200\" rx=\"8\"/>\n  <rect class=\"d-box\" x=\"588\" y=\"34\" width=\"96\" height=\"200\" rx=\"8\"/>\n  <path class=\"d-line d-dashed\" d=\"M372 118 L692 118\"/>\n  <path class=\"d-line d-dashed\" d=\"M372 152 L692 152\"/>\n  <rect class=\"d-box-primary\" x=\"388\" y=\"44\" width=\"80\" height=\"24\" rx=\"4\"/>\n  <rect class=\"d-box-primary\" x=\"492\" y=\"44\" width=\"80\" height=\"48\" rx=\"4\"/>\n  <rect class=\"d-box-primary\" x=\"596\" y=\"44\" width=\"80\" height=\"72\" rx=\"4\"/>\n  <rect class=\"d-box-accent\" x=\"388\" y=\"124\" width=\"80\" height=\"20\" rx=\"4\"/>\n  <rect class=\"d-box-accent\" x=\"492\" y=\"124\" width=\"80\" height=\"20\" rx=\"4\"/>\n  <rect class=\"d-box-accent\" x=\"596\" y=\"124\" width=\"80\" height=\"20\" rx=\"4\"/>\n  <text class=\"d-label-muted\" x=\"420\" y=\"252\">صفوف مشتركة ومتحاذية</text>\n</svg><figcaption>دون الـ subgrid تحدّد كل بطاقة أحجام صفوفها، ومعه تتشارك صفوف الأب</figcaption></figure>\n<p>لاحظ أن الأب لا يعلن <code dir=\"ltr\">grid-template-rows</code> أبدًا. لا يحتاج إلى ذلك: امتداد البطاقات ينشئ صفوفًا ضمنية، وتتحدّد أحجام هذه الصفوف من المحتوى الذي تضعه فيها الـ subgrids. وكل صف جديد من البطاقات يحصل على tracks أربعة خاصة به، فتصطفّ البطاقات في الصف البصري الثاني فيما بينها لا مع الصف الأول، وهذا ما تريده.</p>\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>نسيان الامتداد (span)</span></p>\n<p><code dir=\"ltr\">grid-template-rows: subgrid</code> على بطاقة لا تمتدّ إلا على صف واحد من الأب تعطي الـ subgrid track واحدًا يتشاركه. لا يستطيع الـ subgrid إنشاء صفوف إضافية في الاتجاه الذي يتبع فيه الأب، فيوضع الأبناء الأربعة في ذلك الصف الوحيد ويتكدّسون فوق بعضهم. يجب أن يطابق الامتداد عدد الأجزاء. وإن اختلفت البطاقات في عدد أجزائها (بعضها بلا ملخّص)، فاحتفظ بالخانات واترك الفارغة فارغة، أو أعطِ الجزء الناقص صفًا صريحًا بـ <code dir=\"ltr\">grid-row</code>.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">الفجوات والخطوط والأعمدة</h2>\n<p>يرث الـ subgrid الـ <code dir=\"ltr\">gap</code> من الأب. الأب هنا يستخدم 24px بين البطاقات، وهذا أكثر بكثير مما ينبغي بين العنوان وملخّصه، لذا تتجاوز البطاقة <code dir=\"ltr\">row-gap</code> في الـ tracks الخاصة بها. أما المسافة <em>بين</em> البطاقات فلا تتأثّر.</p>\n<p>ويعمل الـ subgrid على الأعمدة أيضًا. حالة كلاسيكية في Waypoint هي نموذج الملف الشخصي للمتحدّث: التسميات في عمود، والحقول في العمود التالي، وعمود التسميات بالعرض نفسه عبر عدّة fieldsets. جعل كل fieldset <code dir=\"ltr\">grid-column: span 2; grid-template-columns: subgrid</code> يعطي كل fieldset أعمدة النموذج الخارجي، فتصطفّ التسميات حتى الأسفل. وخطوط الشبكة المسمّاة في الأب مرئية أيضًا داخل الـ subgrid، لذا تظل <code dir=\"ltr\">grid-column: content-start / content-end</code> تعمل بمستوى أدنى.</p>\n<aside class=\"callout callout-why\" 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\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><circle cx=\"12\" cy=\"12\" r=\"6\"/><circle cx=\"12\" cy=\"12\" r=\"2\"/></svg><span><span class=\"callout-kind\">لماذا يهمّ هذا</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>لماذا يهمّ هذا</span></p>\n<p>قبل الـ subgrid، كانت محاذاة البطاقات طلبًا تصميميًا يضطر مطوّرو الواجهات الأمامية إلى رفضه أو تزييفه. الـ subgrid ضمن Baseline منذ سبتمبر 2023 (Chrome 117 وFirefox 71 وSafari 16) ومتاح على نطاق واسع منذ مارس 2026، لذا تستطيع أن تقول نعم. وفي المتصفّح القديم تعود البطاقات إلى شبكات عادية متراصّة: مقروءة، لكنها غير متحاذية.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">دورك الآن</h2>\n<p>يعطيك التمرين ثلاث بطاقات جلسات بعناوين مختلفة الطول. حوّل كل بطاقة إلى subgrid للصفوف لتصطفّ الملخّصات وتسميات القاعات عبر الصف. تقارن الفحوصات المواضع الرأسية لتلك الأجزاء عبر البطاقات. ويبقى الدرس التالي مع الأحجام: <code dir=\"ltr\">min()</code> و<code dir=\"ltr\">max()</code> و<code dir=\"ltr\">clamp()</code> والكلمات المفتاحية التي تترك للمحتوى أن يقرّر حجم الأشياء.</p>\n","toc":[{"id":"sec-1","text":"لماذا لا تصطفّ الشبكات المتداخلة","level":2},{"id":"sec-2","text":"استعارة صفوف الأب","level":2},{"id":"sec-3","text":"الفجوات والخطوط والأعمدة","level":2},{"id":"sec-4","text":"دورك الآن","level":2}],"takeaways":["الشبكة المتداخلة التي لها <code dir=\"ltr\">grid-template-rows: subgrid</code> تستخدم صفوف الـ tracks الخاصة بالأب بدل أن تنشئ صفوفها، فيتشارك المحتوى في البطاقات الشقيقة الصفوف نفسها.","يجب أن يمتدّ العنصر الذي يستخدم الـ subgrid على عدد من tracks الأب يساوي عدد أجزائه، مثل <code dir=\"ltr\">grid-row: span 4</code> لبطاقة من أربعة أجزاء.","يرث الـ subgrid الفجوة (gap) من الأب افتراضيًا، ويستطيع تجاوزها بـ <code dir=\"ltr\">row-gap</code> أو <code dir=\"ltr\">column-gap</code> خاصة به.","الـ subgrid ضمن Baseline منذ سبتمبر 2023 ومتاح على نطاق واسع منذ مارس 2026، لذا لم تعد تخطيطات البطاقات المتحاذية تحتاج إلى ارتفاعات ثابتة أو قياسات بـ JavaScript."],"further":[{"title":"Subgrid (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout/Subgrid"},{"title":"CSS subgrid (web.dev)","url":"https://web.dev/articles/css-subgrid"}],"quiz":[{"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\">.sessions</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><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 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\">3</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\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><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 style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid-template-rows</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">subgrid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n","options":[{"text":"البطاقة لا تمتدّ إلا على صف واحد من صفوف الأب، فليس لدى الـ subgrid إلا track واحد يتشاركه.","why":"صحيح. الـ subgrid لا يتبنّى إلا tracks الأب التي يمتدّ عليها، ولا يستطيع إضافة صفوف ضمنية خاصة به. ومع track واحد، يقع الأبناء الأربعة في الصف نفسه ويتراكبون."},{"text":"<code dir=\"ltr\">subgrid</code> تعمل على الأعمدة فقط لا على الصفوف.","why":"<code dir=\"ltr\">subgrid</code> تعمل على أيّ من المحورين أو على كليهما: <code dir=\"ltr\">grid-template-rows: subgrid</code> و<code dir=\"ltr\">grid-template-columns: subgrid</code>."},{"text":"الأب يحتاج إلى <code dir=\"ltr\">grid-template-rows: subgrid</code> هو الآخر.","why":"الأب هو الشبكة التي تملك الـ tracks؛ والشبكة المتداخلة وحدها تستخدم الكلمة المفتاحية <code dir=\"ltr\">subgrid</code>."}],"answer":0},{"q":"<p>ما الطريقة الأمتن لجعل تسمية القاعة في كل بطاقة تصطفّ عبر الصف حين تلتفّ العناوين على أعداد مختلفة من الأسطر؟</p>","options":[{"text":"أعطِ كل عنوان ارتفاعًا ثابتًا <code dir=\"ltr\">height: 3em</code>.","why":"السطر الرابع من العنوان سيفيض، والعنوان ذو السطر الواحد يترك فراغًا؛ الارتفاعات الثابتة تنكسر لحظة يتغيّر المحتوى."},{"text":"قِس أطول عنوان بـ JavaScript واضبط البقية لتطابقه.","why":"ينجح، لكنه بطيء، ويُعاد تشغيله مع كل تغيير في الحجم وكل تحميل للخطوط، وهو بالضبط العمل الذي يؤديه الـ subgrid الآن في CSS."},{"text":"اجعل كل بطاقة subgrid للصفوف يمتدّ على أربعة صفوف من الأب.","why":"صحيح. كل البطاقات في الصف تتشارك الـ tracks الأربعة نفسها، فيكبر كل track ليتّسع لأطول محتوى، ويصطفّ كل ما تحته."}],"answer":2},{"q":"<p>للشبكة الأب <code dir=\"ltr\">gap: 24px</code>، والبطاقات التي تستخدم الـ subgrid تبدو متباعدة أكثر من اللازم من الداخل. ماذا تغيّر؟</p>","options":[{"text":"اضبط <code dir=\"ltr\">gap: 0</code> على الشبكة الأب.","why":"هذا يزيل أيضًا المسافة بين البطاقات نفسها، وهي التي أردت الإبقاء عليها."},{"text":"اضبط <code dir=\"ltr\">row-gap: 8px</code> على البطاقة التي تستخدم الـ subgrid.","why":"صحيح. الـ subgrid يرث فجوات الأب افتراضيًا، لكنه يستطيع تجاوزها في الـ tracks الخاصة به."},{"text":"أضف margins سالبة إلى أبناء البطاقة.","why":"الـ margins السالبة تحارب التخطيط بدل أن تضبطه، وتنكسر حين تتغيّر الفجوة."},{"text":"لا شيء؛ الفجوة الموروثة لا يمكن تغييرها في الـ subgrid.","why":"الفجوة يمكن تجاوزها؛ أحجام الـ tracks وحدها هي التي تأتي من الأب."}],"answer":1}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<section class=\"sessions\">\n  <article class=\"session-card\">\n    <p class=\"time\">09:30</p>\n    <h3>Subgrid</h3>\n    <p class=\"abstract\">Aligning card content across a row without fixed heights.</p>\n    <p class=\"room\">Room A</p>\n  </article>\n  <article class=\"session-card\">\n    <p class=\"time\">10:15</p>\n    <h3>Container Queries in a Design System With Forty Components</h3>\n    <p class=\"abstract\">What changed when every component started measuring itself.</p>\n    <p class=\"room\">Room B</p>\n  </article>\n  <article class=\"session-card\">\n    <p class=\"time\">11:00</p>\n    <h3>Color Spaces for Humans Who Ship Interfaces Every Day of the Week</h3>\n    <p class=\"abstract\">oklch(), color-mix() and palettes that stay accessible.</p>\n    <p class=\"room\">Main hall</p>\n  </article>\n</section>","css":".sessions {\n  width: 660px; /* fixed for this exercise */\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 20px;\n}\n.session-card {\n  padding: 12px;\n  border: 1px solid #e5e7eb;\n  border-radius: 12px;\n}\n.session-card > * { margin: 0; }\n.time { color: #6b7280; font-size: 0.85rem; }\nh3 { font-size: 1rem; }\n.room { font-weight: 600; color: #6d28d9; }\n\n/* Make each card a row subgrid here */\n"},"solution":{"html":"<section class=\"sessions\">\n  <article class=\"session-card\">\n    <p class=\"time\">09:30</p>\n    <h3>Subgrid</h3>\n    <p class=\"abstract\">Aligning card content across a row without fixed heights.</p>\n    <p class=\"room\">Room A</p>\n  </article>\n  <article class=\"session-card\">\n    <p class=\"time\">10:15</p>\n    <h3>Container Queries in a Design System With Forty Components</h3>\n    <p class=\"abstract\">What changed when every component started measuring itself.</p>\n    <p class=\"room\">Room B</p>\n  </article>\n  <article class=\"session-card\">\n    <p class=\"time\">11:00</p>\n    <h3>Color Spaces for Humans Who Ship Interfaces Every Day of the Week</h3>\n    <p class=\"abstract\">oklch(), color-mix() and palettes that stay accessible.</p>\n    <p class=\"room\">Main hall</p>\n  </article>\n</section>","css":".sessions {\n  width: 660px; /* fixed for this exercise */\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 20px;\n}\n.session-card {\n  padding: 12px;\n  border: 1px solid #e5e7eb;\n  border-radius: 12px;\n}\n.session-card > * { margin: 0; }\n.time { color: #6b7280; font-size: 0.85rem; }\nh3 { font-size: 1rem; }\n.room { font-weight: 600; color: #6d28d9; }\n\n.session-card {\n  display: grid;\n  grid-row: span 4;\n  grid-template-rows: subgrid;\n  row-gap: 8px;\n}\n"},"checks":[{"id":"three-across","test":"return new Set($$('.session-card').map((el) => Math.round(el.getBoundingClientRect().top))).size === 1;"},{"id":"uses-subgrid","test":"return $$('.session-card').every((el) => style(el, 'grid-template-rows').startsWith('subgrid'));"},{"id":"abstracts-align","test":"const tops = (sel) => $$(sel).map((el) => el.getBoundingClientRect().top); const same = (arr) => Math.max(...arr) - Math.min(...arr) < 1; return same(tops('.abstract'));"},{"id":"rooms-align","test":"const tops = (sel) => $$(sel).map((el) => el.getBoundingClientRect().top); const same = (arr) => Math.max(...arr) - Math.min(...arr) < 1; return same(tops('.room'));"},{"id":"no-overlap","test":"return $$('.session-card').every((card) => { const kids = [...card.children].map((c) => c.getBoundingClientRect()); return kids.every((r, i) => i === 0 || r.top >= kids[i - 1].bottom - 0.5); });"}],"title":"اجعل بطاقات الجلسات تصطفّ","prompt":"<p>البطاقات الثلاث موضوعة في شبكة من ثلاثة أعمدة، لكن عناوينها تلتفّ على أعداد مختلفة من الأسطر، فتقع الملخّصات وتسميات القاعات على ارتفاعات مختلفة. اجعل كل <code dir=\"ltr\">.session-card</code> <strong>subgrid للصفوف</strong> يمتدّ على الأجزاء الأربعة (الوقت والعنوان والملخّص والقاعة)، بحيث يبدأ كل ملخّص على الارتفاع نفسه وتصطفّ كل تسمية قاعة. أبقِ البطاقات جنبًا إلى جنب ولا تستخدم ارتفاعات ثابتة.</p>\n","hints":["يجب أن تشغل البطاقة أربعة صفوف من الشبكة الأب قبل أن تستطيع استعارتها.","تصريحان على البطاقة يؤدّيان معظم العمل: امتداد واحد و<code dir=\"ltr\">subgrid</code> واحدة. وتحتاج البطاقة أيضًا إلى <code dir=\"ltr\">display: grid</code>.","<code dir=\"ltr\">.session-card { display: grid; grid-row: span 4; grid-template-rows: subgrid; }</code> (أضف <code dir=\"ltr\">row-gap</code> إن بدت المسافات واسعة)."],"explanation":"<p><code dir=\"ltr\">grid-row: span 4</code> تجعل كل بطاقة تشغل أربعة صفوف من شبكة <code dir=\"ltr\">.sessions</code>، و<code dir=\"ltr\">grid-template-rows: subgrid</code> تجعل البطاقة تستخدم تلك الصفوف بدل إنشاء صفوفها الخاصة. أصبح حجم كل صف في الأب يتحدّد الآن بأطول عنصر وُضع فيه من البطاقات الثلاث، فيتّسع صف العنوان لأطول عنوان، ويبدأ كل ملخّص وكل تسمية قاعة على الخط نفسه. ودون الامتداد يكون للبطاقة track واحد تتشاركه، فيوضع أبناؤها كلهم في ذلك الصف الواحد ويتراكبون.</p>\n","checkLabels":{"three-across":"البطاقات ما زالت جنبًا إلى جنب","uses-subgrid":"كل بطاقة تستخدم grid-template-rows: subgrid","abstracts-align":"كل الملخّصات تبدأ على الارتفاع نفسه","rooms-align":"كل تسميات القاعات تصطفّ","no-overlap":"لا شيء يتراكب داخل أيّ بطاقة"}},"words":596,"readMinutes":4}