أتقن شبكة CSS الفرعية (Subgrid) مع هذا الدليل الشامل. تعلم كيفية إنشاء تخطيطات ويب معقدة ومنسقة بدقة وقابلة للصيانة لجمهور عالمي. يتضمن أمثلة عملية وأفضل الممارسات.
شبكة CSS الفرعية (Subgrid): دليل تفصيلي لتكوين التخطيطات المتقدمة
لسنوات، استغل مطورو ومصممو الويب قوة شبكة CSS لإنشاء تخطيطات متطورة ثنائية الأبعاد بتحكم ومرونة غير مسبوقين. لقد أحدثت الشبكة ثورة في طريقة تفكيرنا في بنية صفحات الويب، مبتعدة بنا عن قيود الخصائص العائمة (floats) والطبيعة أحادية البعد لـ Flexbox. ومع ذلك، حتى مع قوتها، ظل هناك تحدٍ مستمر: محاذاة العناصر داخل الشبكات المتداخلة مع الشبكة الرئيسية الأم. كان هذا مصدر إحباط شائعًا، وغالبًا ما كان يؤدي إلى حلول بديلة معقدة، أو حسابات يدوية، أو التخلي عن بنية الشبكة المتداخلة تمامًا. وهنا يأتي دور شبكة CSS الفرعية (Subgrid)، الميزة التي طال انتظارها والتي تحل هذه المشكلة تحديدًا بأناقة، مما يفتح مستوى جديدًا من الدقة والتطور في تكوين التخطيط.
هذا الدليل الشامل مصمم لجمهور عالمي من مطوري الواجهة الأمامية، ومصممي الويب، ومهندسي واجهة المستخدم. سوف نستكشف ماهية شبكة CSS الفرعية، وسبب أهميتها، وكيفية استخدامها، متنقلين من المفاهيم الأساسية إلى التطبيقات العملية المتقدمة. بحلول النهاية، لن تفهم Subgrid فحسب، بل ستكون مجهزًا أيضًا لاستخدامها لبناء تخطيطات أكثر قوة وقابلية للصيانة ومنسقة بشكل جميل.
التحدي قبل Subgrid: معضلة الشبكة المتداخلة
لكي نقدّر تمامًا ما تقدمه Subgrid، يجب أن نفهم أولاً العالم بدونها. تخيل أن لديك تخطيط شبكة رئيسي لمحتوى صفحتك. وضمن أحد عناصر الشبكة، تحتاج إلى إنشاء شبكة أخرى - شبكة متداخلة. هذا نمط شائع جدًا، خاصة في التصميم القائم على المكونات.
لنأخذ مثالاً على تخطيط بطاقة نموذجي. لديك حاوية تحتوي على عدة بطاقات، وهذه الحاوية هي شبكة CSS. كل بطاقة هي عنصر في الشبكة. وداخل كل بطاقة، تريد أيضًا استخدام شبكة لتنظيم محتواها - رأس، وجسم رئيسي، وتذييل.
بدون Subgrid، لا تكون للشبكة المتداخلة داخل البطاقة أي دراية بخطوط الشبكة للحاوية الأم. فهي تنشئ سياق تنسيق شبكة مستقل خاص بها. هذا يعني أن المسارات (الأعمدة والصفوف) التي تحددها داخل البطاقة معزولة تمامًا عن مسارات الحاوية الرئيسية.
مثال مرئي للمشكلة
تخيل قائمة منتجات حيث يكون كل منتج عبارة عن بطاقة. تريد أن تكون عناوين المنتجات متوازية أفقيًا عبر جميع البطاقات، وأن تكون أزرار "أضف إلى السلة" في أسفل كل بطاقة متوازية أيضًا، بغض النظر عن طول الوصف في المنتصف. باستخدام شبكة متداخلة قياسية، يكاد يكون من المستحيل تحقيق ذلك دون اللجوء إلى ارتفاعات ثابتة أو حسابات JavaScript.
إليك مثال مبسط لهذا السيناريو:
بنية HTML:
<div class="card-container">
<div class="card">
<h3>Product A</h3>
<p>A short, concise description.</p>
<button>Add to Cart</button>
</div>
<div class="card">
<h3>Product B</h3>
<p>This product has a much longer description that will wrap onto multiple lines, causing alignment issues for the elements below it.</p>
<button>Add to Cart</button>
</div>
<div class="card">
<h3>Product C</h3>
<p>Another description.</p>
<button>Add to Cart</button>
</div>
</div>
CSS (بدون Subgrid):
.card-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.card {
border: 1px solid #ccc;
padding: 15px;
display: grid;
grid-template-rows: auto 1fr auto; /* Header, Body (stretches), Footer */
gap: 10px;
}
.card h3 {
/* No special styling needed for position */
}
.card p {
/* This will stretch due to 1fr */
}
.card button {
align-self: end; /* Tries to push button to the bottom of its grid area */
}
في هذا المثال، سيكون الزر في البطاقة الثانية في مستوى أدنى من الأزرار في البطاقات الأخرى لأن نص الوصف الخاص به يشغل مساحة أكبر. الشبكة الداخلية لكل بطاقة مستقلة تمامًا. وحدة `1fr` لصف الفقرة تنطبق فقط ضمن سياق الارتفاع المتاح لتلك البطاقة الواحدة. لا يوجد خط شبكة مشترك لتتم محاذاة الأزرار عليه. هذه هي المشكلة التي صُممت Subgrid لحلها بالضبط.
تقديم شبكة CSS الفرعية (Subgrid): القطعة المفقودة للمحاذاة المثالية
شبكة CSS الفرعية هي قيمة لخاصيتي `grid-template-columns` و `grid-template-rows`. عند تطبيقها على عنصر شبكة (والذي يصبح بدوره حاوية شبكة)، فإنها توجه هذا العنصر إلى عدم إنشاء قوائم مسارات جديدة خاصة به. بدلاً من ذلك، فإنه يستعير ويعتمد مسارات الشبكة من أبيه المباشر.
ما هي Subgrid، من الناحية الفنية؟
في جوهرها، تقوم Subgrid بإنشاء رابط مباشر بين شبكة متداخلة وشبكتها الأم. تصبح الشبكة المتداخلة مشاركًا في سياق تنسيق شبكة الأب للبعد المحدد (الصفوف أو الأعمدة أو كليهما). يمكن بعد ذلك وضع العناصر الأبناء للعنصر ذي الشبكة الفرعية على هذه الشبكة الموروثة، مما يسمح لها بالمحاذاة مع عناصر أخرى خارج أبيها المباشر، ولكن ضمن نفس الشبكة الرئيسية.
النقطة الأساسية هي: الشبكة الفرعية لا تحدد مساراتها الخاصة؛ بل تستخدم مسارات أبيها.
الكلمة المفتاحية `subgrid`: الصياغة والاستخدام
الصياغة بسيطة بشكل جميل. يمكنك استخدام الكلمة المفتاحية `subgrid` كقيمة لـ `grid-template-columns` أو `grid-template-rows` أو كليهما، على عنصر يكون في نفس الوقت عنصر شبكة وحاوية شبكة.
لنفترض أن عنصرًا ابنًا `.nested-grid` هو عنصر داخل `.parent-grid`. لجعله شبكة فرعية:
.parent-grid {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* Example parent tracks */
grid-template-rows: 100px auto 200px; /* Example parent tracks */
}
.nested-grid {
/* This item must span the tracks it wants to use */
grid-column: 1 / 4; /* Spans all 3 columns of the parent */
grid-row: 2 / 3; /* Sits in the second row of the parent */
/* Now, we activate subgrid */
display: grid;
grid-template-columns: subgrid; /* Inherits the 3 column tracks from parent */
grid-template-rows: subgrid; /* Inherits the single 'auto' row track from parent */
}
نقطة حاسمة يجب تذكرها: لكي ترث الشبكة الفرعية المسارات، يجب أن تشغلها أولاً. في المثال أعلاه، يمتد `.nested-grid` على جميع الأعمدة الثلاثة لأبيه. لذلك، عندما نضبط `grid-template-columns: subgrid;`، فإنه يكتسب الوصول إلى تلك المسارات الثلاثة نفسها. يمكن الآن وضع أبنائه باستخدام خطوط الشبكة من 1 إلى 4 لشبكة أعمدة الأب.
دعم المتصفحات والتحسين التدريجي
حتى وقت كتابة هذا المقال، تتمتع Subgrid بدعم قوي عبر المتصفحات الحديثة، بما في ذلك Firefox و Chrome و Edge و Safari. هذا يجعلها أداة قابلة للتطبيق لمواقع الإنتاج التي تستهدف قاعدة مستخدمين عالمية. ومع ذلك، كما هو الحال مع أي ميزة CSS حديثة، من الحكمة مراعاة المستخدمين على المتصفحات القديمة.
التحسين التدريجي هو الاستراتيجية المثالية هنا. يمكننا استخدام القاعدة `@supports` في CSS لتوفير تخطيط بديل قوي للمتصفحات التي لا تفهم Subgrid، ثم تطبيق التخطيط المدعوم بـ Subgrid لتلك التي تفهمها.
/* --- Fallback for older browsers --- */
.card {
display: flex;
flex-direction: column;
justify-content: space-between; /* A good flex fallback */
}
/* --- Subgrid enhancement for modern browsers --- */
@supports (grid-template-rows: subgrid) {
.card {
display: grid;
grid-template-rows: subgrid; /* Override the flex display */
grid-row: span 3; /* Assumes parent grid has 3 rows for header, content, footer */
}
}
يضمن هذا النهج تجربة وظيفية ومقبولة للجميع، مع تقديم تخطيط متفوق ومنسق تمامًا لغالبية المستخدمين على المتصفحات الحديثة.
الغوص العملي العميق: Subgrid في العمل
النظرية ضرورية، لكن رؤية Subgrid وهي تحل مشاكل العالم الحقيقي هو المكان الذي تتجلى فيه قوتها حقًا. دعنا نعود إلى مثال مكون البطاقة ونصلحه باستخدام Subgrid.
مثال 1: مكون البطاقة المنسق تمامًا
هدفنا هو جعل رؤوس البطاقات ومناطق المحتوى والتذييلات متوازية عبر جميع البطاقات، مما يخلق خطوطًا أفقية نظيفة، بغض النظر عن طول المحتوى.
أولاً، نحتاج إلى تعديل شبكتنا الأم. بدلاً من تحديد الأعمدة، سنحدد أيضًا صفوفًا تتوافق مع الأقسام المطلوبة لبطاقاتنا (الرأس، الجسم، التذييل).
HTML الجديد (لا حاجة للتغييرات):
<div class="card-container">
<!-- Cards go here, same as before -->
</div>
CSS الجديد (مع Subgrid):
.card-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* Define rows for our card structure */
grid-template-rows: auto 1fr auto; /* Row for headers, flexible body, row for footers */
gap: 20px;
}
.card {
border: 1px solid #ccc;
padding: 15px;
/* --- The Subgrid Magic --- */
display: grid;
/* The card itself needs to span all the rows it will use */
grid-row: 1 / 4; /* Span all three rows defined in the parent */
/* Now, inherit those rows */
grid-template-rows: subgrid;
}
/* Place the card's children onto the inherited parent grid */
.card h3 {
grid-row: 1; /* Place in the first row of the parent's grid */
}
.card p {
grid-row: 2; /* Place in the second (flexible) row */
}
.card button {
grid-row: 3; /* Place in the third row */
align-self: end; /* Optional: align to bottom within that row */
}
ماذا حدث للتو؟
- تحدد `.card-container` الآن شبكة من ثلاثة صفوف: صف بحجم `auto` للرؤوس، وصف مرن `1fr` للمحتوى الرئيسي، وصف آخر بحجم `auto` للأزرار.
- يُطلب من كل `.card` أن يمتد على جميع هذه الصفوف الثلاثة (`grid-row: 1 / 4`).
- بشكل حاسم، قمنا بتعيين `display: grid` و `grid-template-rows: subgrid` على `.card`. هذا يخبر البطاقة: "لا تنشئي صفوفك الخاصة. استخدمي الصفوف الثلاثة التي تمتدين عليها من أبيك."
- الآن، يتم وضع `h3` و `p` و `button` داخل كل بطاقة على نفس الشبكة المشتركة. `h3` من البطاقة الأولى في نفس المسار مثل `h3` من البطاقة الثانية. و`button` من البطاقة الأولى في نفس المسار مثل الزر من البطاقة الثانية. النتيجة؟ محاذاة أفقية مثالية عبر المكون بأكمله.
هذا تغيير ثوري. لقد حققنا هدف محاذاة معقدًا باستخدام CSS تصريحية بسيطة، بدون حيل، مع الحفاظ على بنية HTML نظيفة وذات دلالة.
مثال 2: محاذاة حقول النموذج في تخطيط معقد
النماذج هي مجال آخر تكون فيه المحاذاة حاسمة لتجربة مستخدم نظيفة. تخيل قسمًا من الصفحة هو عنصر شبكة، وداخل هذا القسم، لديك نموذج به تسميات وحقول إدخال تريد محاذاتها مع عناصر أخرى على الصفحة.
بنية HTML:
<div class="page-layout">
<aside>... sidebar content ...</aside>
<main>
<h1>Profile Settings</h1>
<form class="profile-form">
<label for="name">Full Name</label>
<input type="text" id="name" />
<label for="email">Email Address</label>
<input type="email" id="email" />
<label for="country">Country/Region</label>
<input type="text" id="country" />
</form>
</main>
</div>
CSS باستخدام Subgrid للأعمدة:
.page-layout {
display: grid;
/* A common layout: sidebar, main content with two sub-columns */
grid-template-columns: 200px [main-start] 150px 1fr [main-end];
gap: 30px;
}
main {
grid-column: main-start / main-end; /* Span the two main content columns */
display: grid;
/* This is the key: inherit the parent's columns */
grid-template-columns: subgrid;
/* We can define our own rows as needed */
grid-auto-rows: min-content;
align-content: start;
}
main h1 {
/* Let the heading span both inherited columns */
grid-column: 1 / 3;
}
.profile-form {
/* This form is also a grid item within 'main' */
grid-column: 1 / 3;
display: grid;
/* And we make IT a subgrid too! */
grid-template-columns: subgrid;
gap: 15px;
grid-auto-rows: min-content;
}
/* Now place labels and inputs on the inherited page-level grid */
.profile-form label {
grid-column: 1; /* Align to the first column (150px from .page-layout) */
text-align: right;
}
.profile-form input {
grid-column: 2; /* Align to the second column (1fr from .page-layout) */
}
في هذا المثال المتقدم، لدينا شبكة فرعية متداخلة. يصبح العنصر `main` شبكة فرعية ليرث مسارات الأعمدة من `.page-layout`. ثم، يصبح `form` بداخله أيضًا شبكة فرعية، ويرث نفس تلك المسارات مرة أخرى. هذا يسمح بوضع تسميات وحقول إدخال النموذج مباشرة على شبكة الصفحة الرئيسية، مما يضمن محاذاتها تمامًا مع هيكل الصفحة العام المحدد في الحاوية ذات المستوى الأعلى. كان هذا المستوى من التحكم التكويني لا يمكن تصوره سابقًا باستخدام CSS النقي.
Subgrid للصفوف والأعمدة: الوراثة أحادية البعد مقابل ثنائية الأبعاد
ليس عليك استخدام Subgrid لكلا المحورين في وقت واحد. يمكنك اختيار وراثة المسارات للأعمدة فقط، أو الصفوف فقط، أو كليهما. هذا يوفر تحكمًا دقيقًا في تخطيطاتك.
الشبكات الفرعية للأعمدة: `grid-template-columns: subgrid;`
هذا مثالي لمحاذاة العناصر أفقيًا عبر المكونات، مثل مثال النموذج أعلاه. عند استخدام `grid-template-columns: subgrid;`، يجب عليك تحديد مسارات الصفوف الخاصة بك باستخدام قيم قياسية مثل `auto` أو `1fr` أو قيم البكسل (على سبيل المثال، `grid-template-rows: auto 1fr;`). ترث الشبكة المتداخلة الأعمدة لكنها مسؤولة عن تحديد حجم وعدد صفوفها.
الشبكات الفرعية المستندة إلى الصفوف: `grid-template-rows: subgrid;`
هذا مثالي لمحاذاة العناصر رأسيًا، كما فعلنا في مثال مكون البطاقة. إنه ممتاز لضمان محاذاة الأقسام الأفقية للمكونات المختلفة. عند استخدام `grid-template-rows: subgrid;`، يجب عليك تحديد مسارات الأعمدة الخاصة بك (على سبيل المثال، `grid-template-columns: 1fr 1fr;`).
الجمع بين الاثنين: الوراثة الكاملة
عندما تقوم بتعيين كل من `grid-template-columns: subgrid;` و `grid-template-rows: subgrid;`، تصبح الشبكة المتداخلة وكيلاً حقيقيًا للشبكة الأم داخل منطقتها المخصصة. فهي لا تحدد أيًا من مساراتها الخاصة. هذا قوي للمكونات التي تحتاج إلى أن تكون محصورة بدقة في جزء من الشبكة الأم مع السماح لأبنائها بالحرية الكاملة في وضعها على بنية الشبكة الموروثة.
فكر في أداة لوحة معلومات. قد تمتد الأداة نفسها على 3 أعمدة وصفين من شبكة لوحة المعلومات الرئيسية. من خلال جعل الأداة شبكة فرعية كاملة، يمكن وضع العناصر داخل الأداة (مثل عنوان المخطط، والمخطط نفسه، والمفتاح) بدقة على تلك الأعمدة الثلاثة والصفين، ومحاذاتها مع العناصر في الأدوات المجاورة.
المفاهيم المتقدمة والفروق الدقيقة
كلما أصبحت أكثر راحة مع Subgrid، ستواجه بعض جوانبها الأكثر دقة وقوة.
Subgrid و `gap`
خاصية `gap` على الشبكة الأم يتم توريثها بواسطة الشبكة الفرعية. المسافة بين المسارات هي جزء من تعريف الشبكة. هذا عادة ما تريده، لأنه يحافظ على تباعد ثابت في جميع أنحاء التخطيط. يمكنك، مع ذلك، تحديد `gap` على حاوية الشبكة الفرعية نفسها. سيؤدي هذا إلى إضافة فجوة إلى الفجوة الموروثة، وهو سلوك يجب الانتباه إليه. في معظم الحالات، سترغب في تحديد الفجوة على الشبكة الأم والسماح للشبكة الفرعية بتوريثها لتحقيق اتساق مثالي.
التحجيم والامتداد في سياق Subgrid
هذه واحدة من أقوى الميزات. عندما تضع عنصرًا داخل شبكة فرعية وتخبره بالامتداد عبر مسارات متعددة (على سبيل المثال، `grid-column: span 2;`)، فإنه يمتد على مسارات الشبكة الأم الأصلية. إنه لا يمتد على مسارين من حاوية الشبكة الفرعية؛ بل يمتد على مسارين ورثتهما الشبكة الفرعية.
هذا يسمح بمرونة تكوينية لا تصدق. يمكن جعل عنصر في عمق شجرة DOM يتماشى ويمتد عبر بنية الصفحة عالية المستوى، متجاوزًا الحدود المرئية لحاويته المباشرة بطريقة يمكن التحكم فيها والتنبؤ بها. هذا رائع لإنشاء تخطيطات ديناميكية بأسلوب المجلات حيث قد تمتد صورة على عدة أعمدة من شبكة المقال الرئيسية، على الرغم من أنها متداخلة داخل عنصر `figure`.
اعتبارات إمكانية الوصول
واحدة من الفوائد العظيمة لشبكة CSS، والتي تمتد إلى Subgrid، هي فصل ترتيب المصدر عن العرض المرئي. مع Subgrid، يمكنك الحفاظ على بنية مستند HTML منطقية وسهلة الوصول (على سبيل المثال، عنوان يتبعه محتواه) مع استخدام الشبكة لتحقيق تخطيط مرئي أكثر تعقيدًا أو إبداعًا.
لأن Subgrid تساعدك على تجنب حيل التخطيط، فإنها غالبًا ما تؤدي إلى HTML أنظف. سيقوم قارئ الشاشة بتصفح مستند منطقي، بينما يرى المستخدم المرئي تصميمًا منسقًا تمامًا. على سبيل المثال، في تخطيط بطاقاتنا، يظل HTML لكل بطاقة وحدة منطقية قائمة بذاتها (`h3` -> `p` -> `button`). تقوم Subgrid ببساطة بتنسيق المحاذاة المرئية بين هذه الوحدات دون تغيير تدفق المستند، وهو مكسب كبير لإمكانية الوصول ومبدأ أساسي في تطوير الويب الحديث.
مستقبل تخطيط CSS: مكان Subgrid في النظام البيئي
Subgrid ليست بديلاً لـ Flexbox أو شبكة CSS العادية. إنها تحسين قوي يملأ فجوة محددة وحاسمة. يدور نظام تخطيط CSS الحديث حول استخدام الأداة المناسبة للمهمة:
- Flexbox: الأفضل للتخطيطات أحادية البعد، وتوزيع المساحة على طول محور واحد، ومحاذاة العناصر داخل حاوية. مثالي لأشرطة التنقل، ومجموعات الأزرار، والأجزاء الداخلية البسيطة للمكونات.
- شبكة CSS: الأفضل للتخطيطات ثنائية الأبعاد على مستوى الصفحة، وإنشاء علاقات بين الصفوف والأعمدة. الأساس لهيكل صفحتك العام.
- شبكة CSS الفرعية (Subgrid): الجسر بين المكونات المتداخلة وشبكة الصفحة الرئيسية. إنها الأداة التي تلجأ إليها عندما تحتاج العناصر داخل عنصر شبكة إلى المحاذاة مع عناصر خارجه.
بالنظر إلى المستقبل، تعمل Subgrid بشكل جميل مع ميزات CSS الحديثة الأخرى مثل استعلامات الحاوية (Container Queries). يمكن أن يكون لديك مكون يتبنى تخطيط شبكة فرعية عندما تكون حاويته واسعة، ولكنه يتكدس في تخطيط كتلة بسيط أو flex في حاوية ضيقة. هذا المزيج من التخطيط على المستوى الكلي (Grid)، والمحاذاة على مستوى المكون (Subgrid)، والاستجابة المدركة للحاوية (Container Queries) يمنح مطوري الواجهة الأمامية مجموعة أدوات قوية ومعبرة بشكل لا يصدق لبناء الجيل التالي من واجهات الويب.
الخلاصة: احتضن قوة التكوين المنسق
شبكة CSS الفرعية هي أكثر من مجرد ميزة جديدة؛ إنها نقلة نوعية في كيفية تكوين التخطيطات المعقدة على الويب. إنها تحل مشكلة طويلة الأمد بحل أنيق وبديهي، مما يعزز الكود الأنظف، وأوراق الأنماط الأكثر قابلية للصيانة، والتصاميم المرئية المثالية.
من خلال السماح للشبكات المتداخلة بالمشاركة في تخطيط آبائها، تمكننا Subgrid من:
- تحقيق المحاذاة المثالية: ضمان محاذاة العناصر في مكونات منفصلة بشكل لا تشوبه شائبة بدون حيل أو JavaScript.
- كتابة كود أكثر اختصارًا (DRYer): تحديد بنية الشبكة الرئيسية مرة واحدة وجعل العناصر المتداخلة ترثها، وتجنب تعريفات المسارات المتكررة.
- تحسين قابلية الصيانة: يتركز منطق التخطيط في الشبكة الأم، مما يجعل التحديثات والتعديلات المتجاوبة أبسط بكثير.
- تعزيز إمكانية الوصول: إنشاء تخطيطات مرئية متطورة مع الحفاظ على ترتيب مصدر منطقي وذي دلالة.
مع الدعم الواسع للمتصفحات، الآن هو الوقت المثالي للمطورين والمصممين حول العالم لتبني Subgrid في سير عملهم. ابدأ بتحديد المكونات التي ستستفيد من المحاذاة عبر العناصر، وجرب وراثة الصفوف والأعمدة، واستمتع بالرضا عن بناء تخطيطات قوية ومنطقية تحت الغطاء بقدر ما هي جميلة على الشاشة. لقد انتهى عصر التخطيطات المتداخلة المنقوصة؛ لقد بدأ حقًا عصر التكوين المتقدم والمنسق.