تخطَّ إلى المحتوى

🟦 شرح CSS

التخطيط مع Grid

الدرس 20 من 30· ⏱ 8 دقائق قراءة· 🗓 آخر تحديث: ١٩ أكتوبر ٢٠٢٦

CSS Grid نظام تخطيط ثنائي الأبعاد: تقسّم الحاوية إلى صفوف وأعمدة في نفس الوقت، ثم تضع كل عنصر في المكان الذي تريده منها. Flexbox يرتّب العناصر على محور واحد ويترك المحتوى يقرّر الأحجام، أما Grid فتبدأ بالشبكة أولًا ثم تضع المحتوى فيها. لهذا يُستخدم Grid لهيكل الصفحة وللبطاقات المتراصّة، وFlexbox داخل المكوّنات. المقارنة الكاملة بأمثلة في الفرق بين Flexbox و Grid.

كل السلوكيات والأرقام في هذا الدرس مقاسة فعليًا في Chromium.

المصطلحات الأربعة

      خط 1    خط 2    خط 3    خط 4
        │       │       │       │
  خط 1 ─┼───────┼───────┼───────┼─
        │ خلية  │       │       │   ← مسار (صف)
  خط 2 ─┼───────┼───────┼───────┼─
        │       │   منطقة       │
  خط 3 ─┼───────┼───────────────┼─
                  ↑ مسار (عمود)
  • الخطوط (lines): الحدود الفاصلة، مرقّمة من 1. ثلاثة أعمدة = أربعة خطوط.
  • المسارات (tracks): الصف أو العمود بين خطّين.
  • الخلية (cell): تقاطع صف وعمود.
  • المنطقة (area): مستطيل من خلية أو أكثر.

أغلب أخطاء Grid سببها الخلط بين رقم الخط ورقم العمود: grid-column: 1 / 3 تعني "من الخط 1 إلى الخط 3"، أي عمودين.

الحاوية: تعريف الأعمدة

.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr; /* ثلاثة أعمدة متساوية */
  gap: 20px;                          /* المسافة بين الأعمدة والصفوف */
}

fr (fraction) تعني "جزءًا من المساحة المتبقية". ويمكن خلطها مع وحدات ثابتة:

.container {
  grid-template-columns: 250px 1fr;        /* شريط جانبي ثابت + محتوى مرن */
  grid-template-columns: 1fr 2fr;          /* الثاني ضعف الأول */
  grid-template-columns: repeat(4, 1fr);   /* اختصار لـ 1fr 1fr 1fr 1fr */
}

لماذا fr وليس %؟

جرّبنا حاويتين عرضهما 600px وفيهما gap: 20px:

.a { grid-template-columns: 33.33% 33.33% 33.33%; gap: 20px; }
.b { grid-template-columns: 1fr 1fr 1fr;          gap: 20px; }

في الأولى انتهى العمود الثالث عند 640px، أي خرج 40px خارج الحاوية، لأن النسب تُحسب من العرض الكامل ثم تُضاف المسافات فوقها. في الثانية انتهى عند 600px تمامًا، لأن fr تقسم ما يتبقى بعد طرح الـ gap.

العناصر: أين يقع كل عنصر

.item {
  grid-column: 1 / 3;    /* من الخط 1 إلى الخط 3 = عمودان */
  grid-row: 2;           /* الصف الثاني */
}

.wide {
  grid-column: span 2;   /* يمتد على عمودين من حيث يقع تلقائيًا */
}

.full {
  grid-column: 1 / -1;   /* من أول خط إلى آخر خط: كل العرض */
}

الأرقام السالبة تُعدّ من النهاية، فـ -1 هو آخر خط دائمًا مهما كان عدد الأعمدة. هذا أفضل من كتابة 1 / 4 ثم نسيان تعديلها حين تصبح الأعمدة خمسة.

Grid في صفحة عربية: الخط 1 على اليمين

في صفحة اتجاهها dir="rtl" (مثل هذا الموقع)، Grid يتبع اتجاه الكتابة: الخط 1 على اليمين والعمود الأول هو الأيمن.

.layout {
  display: grid;
  grid-template-columns: 100px 200px 300px;
}
.first { grid-column: 1; }

في حاوية عرضها 600px مع dir="rtl"، وقع .first بين 500px و600px، أي في أقصى اليمين وبعرض 100px. هذا يعني أن تخطيطك يُعكس تلقائيًا بين العربية والإنجليزية دون أي سطر CSS إضافي، بشرط ألا تستخدم left وright في أماكن أخرى من التصميم. إن كتبت grid-template-columns: 250px 1fr لشريط جانبي، فسيظهر على اليمين في العربية وعلى اليسار في الإنجليزية، وهذا غالبًا ما تريده.

الشبكة الضمنية: ماذا يحدث للعناصر الزائدة

عرّفت عمودين وصفًّا واحدًا، ووضعت 4 عناصر:

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 50px;
}

العنصران الثالث والرابع لا يختفيان: Grid ينشئ صفوفًا ضمنية (implicit) جديدة لهما. لكن ارتفاع الصف الضمني auto (في تجربتنا 18px، أي ارتفاع النص فقط)، لا 50px. للتحكم فيه:

.container {
  grid-auto-rows: 50px;           /* كل صف ضمني 50px */
  grid-auto-rows: minmax(50px, auto); /* 50px على الأقل، ويكبر مع المحتوى */
}

شبكة متجاوبة بلا media query

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 16px;
}

اقرأها هكذا: "ضع أكبر عدد من الأعمدة يتّسع، كل عمود لا يقل عن 250px، ووزّع الباقي بالتساوي". على الهاتف عمود واحد، وعلى الشاشة الواسعة أربعة أو خمسة، دون سطر @media واحد.

auto-fit أم auto-fill؟

الفرق يظهر فقط حين تكون العناصر أقل من عدد الأعمدة الممكن. حاوية 600px فيها عنصران فقط، مع minmax(100px, 1fr):

الأعمدة المحسوبةالنتيجة
auto-fill100px × 6ستة أعمدة، العنصران بعرض 100px والباقي فارغ
auto-fit300px 300px ثم أعمدة بعرض 0الأعمدة الفارغة تنطوي، والعنصران يتمدّدان لملء العرض
  • auto-fit لبطاقات تريدها أن تملأ السطر دائمًا.
  • auto-fill حين تريد أن تبقى البطاقة بحجمها حتى لو كانت وحدها (قائمة منتجات لا يجب أن يتحوّل فيها منتج وحيد إلى شريط عريض).

المناطق المُسمّاة: التخطيط مرسوم في الكود

.page {
  display: grid;
  grid-template-columns: 250px 1fr;
  grid-template-areas:
    "header  header"
    "sidebar main"
    "footer  footer";
  gap: 16px;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }

@media (max-width: 700px) {
  .page {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main"
      "sidebar"
      "footer";
  }
}

قوتها الحقيقية في الـ media query: غيّرت ترتيب الصفحة كلها على الهاتف (المحتوى قبل الشريط الجانبي) بتعديل الرسم فقط، دون لمس HTML ولا قواعد العناصر. كل منطقة يجب أن تكون مستطيلًا؛ شكل L غير مسموح ويُبطل القاعدة كلها. ولتجاوب على مستوى المكوّن بدل الشاشة، راجع Container Queries.

المحاذاة

.container {
  justify-items: center;  /* محاذاة العناصر داخل خلاياها أفقيًا */
  align-items: center;    /* وعموديًا */
  place-items: center;    /* الاثنان معًا */
}

.item {
  justify-self: end;      /* لعنصر واحد فقط */
}

justify-* على المحور الأفقي (اتجاه السطر)، وalign-* على العمودي. وفي RTL تحترم start وend الاتجاه، فـ justify-self: start تعني اليمين في الصفحة العربية. لتوسيط عنصر واحد داخل حاوية، display: grid; place-items: center; أقصر طريقة في CSS.

subgrid: بطاقات تتطابق صفوفها

مشكلة شائعة: بطاقتان متجاورتان، عنوان الأولى سطر واحد وعنوان الثانية ثلاثة أسطر، فتنزل فقرات البطاقة الثانية أكثر وتبدو الصفوف غير متطابقة. subgrid يجعل البطاقة تستخدم صفوف الشبكة الأم بدل صفوفها الخاصة:

.cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

.card {
  display: grid;
  grid-row: span 3;              /* البطاقة تأخذ 3 صفوف من الأم */
  grid-template-rows: subgrid;   /* وتستخدمها لعنوانها وفقرتها وزرّها */
}

في تجربتنا، مع عنوان قصير في بطاقة وعنوان من ثلاثة أسطر في الأخرى، بدأت الفقرتان عند نفس الارتفاع بالضبط. subgrid مدعوم في كل المتصفحات الرئيسية الحديثة.

نظام 12 عمودًا

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 16px;
}
.col-6 { grid-column: span 6; }  /* نصف العرض */
.col-4 { grid-column: span 4; }  /* الثلث */

هذا ما تقدّمه أطر مثل Bootstrap. مفيد حين يتبع فريق تصميم شبكة ثابتة، لكن لأغلب الصفحات grid-template-columns بقيم حقيقية (250px 1fr) أو auto-fit أبسط وأوضح.

الأخطاء الشائعة

1) محتوى طويل يكسر العمود:

.layout { grid-template-columns: 1fr 1fr; }

وضعنا في العمود الأول <pre> فيه سطر كود طويل لا يلتف. النتيجة: العمود الأول صار 838px والثاني 9px، وخرجت الشبكة من حاوية عرضها 600px. السبب أن 1fr تعني فعليًا minmax(auto, 1fr): العمود لا يصغر عن أطول محتوى غير قابل للالتفاف. الحل:

.layout { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
pre { overflow: auto; }

مع هذا التعديل عاد العمودان إلى 300px و300px، وظهر شريط تمرير داخل <pre> وحده. تذكّر هذا الحل كلما رأيت عمود Grid "يرفض" أن يصغر، خصوصًا مع الكود والجداول والروابط الطويلة.

2) استخدام margin بين العناصر بدل gap: الهوامش تُضاف على أطراف الحاوية أيضًا وتحتاج استثناءات للعنصر الأول والأخير. gap يضع المسافة بين المسارات فقط.

3) نسيان أن grid-column: 1 / 3 عمودان لا ثلاثة: الأرقام أرقام خطوط. استخدم span 3 إن كنت تفكر بعدد الأعمدة.

4) Grid لصف أزرار بسيط: صف من عناصر تريد أن يأخذ كل منها حجم محتواه هو عمل Flexbox. Grid يناسب حين تريد الأعمدة أن تتطابق بين صفوف مختلفة.

افحص الشبكة في المتصفح

في أدوات المطوّر بـ Chrome أو Firefox، اضغط على شارة grid بجانب العنصر في تبويب Elements لتظهر الخطوط مرقّمة فوق الصفحة. هذا أسرع طريقة لترى لماذا وقع عنصر في غير مكانه، وسترى الترقيم يبدأ من اليمين في صفحة RTL.

خلاصة

  • display: grid + grid-template-columns تعرّف الشبكة، وgap للمسافات.
  • fr بدل % لأنها تطرح الـ gap أولًا.
  • الأرقام في grid-column أرقام خطوط، و1 / -1 كل العرض.
  • في RTL الخط 1 على اليمين.
  • repeat(auto-fit, minmax(250px, 1fr)) لشبكة متجاوبة بلا media query.
  • grid-template-areas لتخطيط الصفحة، وsubgrid لمطابقة صفوف البطاقات.
  • عمود لا يصغر؟ minmax(0, 1fr).

بعد هذا الدرس، طبّق Grid وFlexbox معًا لجعل صفحتك تعمل على كل الشاشات في درس التصميم المتجاوب.

شرح التخطيط مع Grid — CSS بالعربي
التخطيط مع Grid — CSS بالعربي · The Code Fix

📚 لمزيد من التعمّق في CSS، راجِع توثيق CSS على MDN.

هل كان هذا الدرس مفيدًا؟