CSS3 والتصميم المتجاوب

الشبكة المتقدمة: Auto-Fill و Auto-Fit و Subgrid

30 دقيقة الدرس 31 من 60

مقدمة الى الشبكة المتجاوبة بدون استعلامات الوسائط

في الدروس السابقة، تعلمت كيفية انشاء تخطيطات شبكة بتعريفات صريحة للاعمدة والصفوف. تعلمت ايضا كيف تتيح لك استعلامات الوسائط اعادة تعريف قوالب الشبكة عند نقاط توقف مختلفة. لكن شبكة CSS تملك قدرة اقوى: يمكنها تلقائيا انشاء عدد الاعمدة التي تناسب المساحة المتاحة، بدون اي استعلام وسائط واحد. يتحقق ذلك من خلال دالة repeat() مع الكلمات المفتاحية auto-fill و auto-fit. هذه الميزات، بالاشتراك مع minmax()، تتيح لك بناء تخطيطات سائلة ومتجاوبة حقا تتكيف بسلاسة مع اي حجم شاشة.

في هذا الدرس، سنتقن auto-fill و auto-fit، ونفهم الفرق الحاسم بينهما، ونستكشف النمط القوي repeat(auto-fill, minmax())، ثم نغوص في ميزة subgrid الثورية التي تسمح للشبكات الفرعية بوراثة تحجيم مسارات الشبكة الام. سنغطي ايضا تخطيطات بنمط الحجارة، والشبكة مع aspect-ratio، وانماط متجاوبة متقدمة تلغي الحاجة لنقاط التوقف تماما.

مراجعة دالة repeat()

قبل الغوص في auto-fill و auto-fit، لنراجع دالة repeat(). رايتها تستخدم مع عدد ثابت: repeat(3, 1fr) تنشئ ثلاثة اعمدة متساوية العرض بالضبط. لكن repeat() اكثر تنوعا من ذلك بكثير. وسيطتها الاولى يمكن ان تكون عددا صحيحا ثابتا، او يمكن ان تكون واحدة من كلمتين مفتاحيتين خاصتين: auto-fill او auto-fit. هذه الكلمات تخبر المتصفح بحساب عدد المسارات ديناميكيا بناء على المساحة المتاحة.

مثال: repeat الثابت مقابل الكلمات المفتاحية التلقائية

/* ثابت: دائما 4 اعمدة بالضبط */
.grid-fixed {
    display: grid;
    grid-template-columns: repeat(4, 250px);
}

/* ديناميكي: عدد اعمدة 250px التي تناسب المساحة */
.grid-dynamic {
    display: grid;
    grid-template-columns: repeat(auto-fill, 250px);
}

مع repeat(4, 250px)، الشبكة تنشئ دائما اربعة اعمدة بعرض 250px لكل منها، بغض النظر عن عرض الحاوية. اذا كانت الحاوية اضيق من 1000px، ستفيض الاعمدة. مع repeat(auto-fill, 250px)، يحسب المتصفح عدد اعمدة 250px التي تناسب عرض الحاوية وينشئ هذا العدد بالضبط. في حاوية 1200px، تحصل على 4 اعمدة (مع 200px من المساحة المتبقية). في حاوية 600px، تحصل على عمودين. التخطيط يتكيف تلقائيا.

auto-fill: انشاء مسارات لملء الحاوية

الكلمة المفتاحية auto-fill تخبر الشبكة بتكرار نمط المسار اكبر عدد ممكن من المرات دون تجاوز الحاوية. اذا كانت الحاوية بعرض 1000px وكل مسار 200px، ينشئ المتصفح 5 اعمدة. السلوك الاساسي لـ auto-fill هو انه ينشئ مسارات حتى لو لم تكن هناك عناصر شبكة لوضعها فيها. المسارات الفارغة تبقى محفوظة وتشغل مساحة في الشبكة.

مثال: auto-fill مع حجم مسار ثابت

.gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, 200px);
    gap: 16px;
}

/* الحاوية بعرض 900px:
   900 / 200 = 4.5 -> 4 اعمدة بعرض 200px
   المساحة المتبقية 100px تبقى في النهاية */

لاحظ انه مع المسارات ذات الحجم الثابت (مثل 200px)، غالبا ينتهي بك الامر بمساحة متبقية في نهاية الصف. الاعمدة تبقى بالضبط 200px، واي مساحة لا تناسب عمودا اخر تبقى فارغة. هنا يصبح minmax() ضروريا.

النمط القوي: repeat(auto-fill, minmax(min, 1fr))

النمط الاكثر فائدة والاوسع استخداما في الشبكة يجمع بين auto-fill و minmax(). دالة minmax() تحدد نطاق حجم للمسار: سيكون على الاقل بالحجم الادنى، وعلى الاكثر بالحجم الاقصى. عندما تستخدم 1fr كحد اقصى، المسارات ستنمو بالتساوي لملء كل المساحة المتاحة.

مثال: النمط الذهبي

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 20px;
}

/* كيف يعمل:
   1. المتصفح يحسب عدد اعمدة 250px التي تناسب المساحة
   2. ينشئ هذا العدد من الاعمدة
   3. كل عمود ينمو بالتساوي (عبر 1fr) لملء المساحة المتبقية

   حاوية 1200px: 4 اعمدة بعرض 300px لكل منها
   حاوية 800px:  3 اعمدة بعرض ~267px لكل منها
   حاوية 550px:  عمودان بعرض 275px لكل منهما
   حاوية 300px:  عمود واحد بعرض 300px

   لا حاجة لاستعلامات وسائط! */

هذا يمكن القول انه اهم نمط شبكة CSS يجب حفظه. ينشئ شبكة متجاوبة تضبط تلقائيا عدد الاعمدة بناء على المساحة المتاحة، مع ضمان ان العناصر لا تصغر ابدا عن الحد الادنى للعرض وتمتد دائما لملء الحاوية بدون مساحة متبقية. يعمل بشكل جميل لشبكات البطاقات وقوائم المنتجات ومعارض الصور واي محتوى متكرر.

نصيحة: القيمة الدنيا في minmax() تحدد نقاط التوقف. حد ادنى 250px يعني تقريبا: عمود واحد تحت 500px، عمودان عند 500-749px، 3 اعمدة عند 750-999px، وهكذا. اضبط هذه القيمة الدنيا للتحكم في متى تلتف الاعمدة. قيم دنيا اصغر تنشئ اعمدة اكثر ابكر؛ قيم دنيا اكبر تنشئ اعمدة اقل.

auto-fit: طي المسارات الفارغة

الكلمة المفتاحية auto-fit تعمل بشكل مطابق تقريبا لـ auto-fill، مع فرق حاسم واحد: auto-fit يطوي المسارات الفارغة الى عرض صفر. هذا يعني انه اذا كان هناك عناصر شبكة اقل من عدد المسارات التي يمكن ان تناسب، فان المسارات الفارغة تختفي، والعناصر الموجودة تمتد لملء عرض الحاوية بالكامل.

مثال: auto-fill مقابل auto-fit مع عناصر قليلة

/* auto-fill: المسارات الفارغة تبقى، العناصر تبقى بالحجم الادنى */
.auto-fill-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 16px;
}

/* auto-fit: المسارات الفارغة تنطوي، العناصر تمتد لملء الحاوية */
.auto-fit-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
}

الفرق يصبح مرئيا فقط عندما يكون هناك عناصر اقل من عدد الاعمدة الممكنة. تخيل حاوية 1200px مع حد ادنى 200px. ستة اعمدة بعرض 200px يمكن ان تناسب. اذا كان لديك 6 عناصر، كلا من auto-fill و auto-fit يتصرفان بشكل متطابق -- كل الاعمدة الستة ممتلئة. لكن اذا كان لديك 3 عناصر فقط:

  • auto-fill: ينشئ 6 اعمدة (لان 6 يمكن ان تناسب). ثلاثة ممتلئة بالعناصر، وثلاثة تبقى فارغة لكنها تشغل مساحة. كل عمود 200px، ولا يوجد تمدد لان الاعمدة الفارغة تمتص المساحة.
  • auto-fit: ينشئ 6 اعمدة مبدئيا، ثم يطوي الثلاثة الفارغة الى 0px. الاعمدة الثلاثة الممتلئة تمتد بالتساوي (عبر 1fr) لملء 1200px بالكامل، مما يجعل كل واحد 400px.

مقارنة بصرية: 3 عناصر في حاوية 1200px

/* auto-fill مع minmax(200px, 1fr): */
/* |--200px--|--200px--|--200px--|--200px--|--200px--|--200px--| */
/* | عنصر 1  | عنصر 2  | عنصر 3  | (فارغ)  | (فارغ)  | (فارغ)  | */

/* auto-fit مع minmax(200px, 1fr): */
/* |------400px------|------400px------|------400px------| */
/* |     عنصر 1      |     عنصر 2      |     عنصر 3      | */
ملاحظة: عندما تكون الشبكة ممتلئة (كل المسارات الممكنة بها عناصر)، auto-fill و auto-fit تنتجان نتائج متطابقة. الفرق يهم فقط عندما يكون هناك عناصر اقل من المسارات المتاحة. اختر auto-fit عندما تريد للعناصر ان تمتد وتملا الصف، و auto-fill عندما تريد للعناصر ان تحافظ على حجم متسق بغض النظر عن العدد.

متى تستخدم auto-fill مقابل auto-fit

الاختيار بين الاثنين يعتمد على نية تصميمك:

  • استخدم auto-fill عندما: تريد احجام عناصر متسقة بغض النظر عن عددها. هذا مثالي لانظمة التصميم حيث يجب ان تكون البطاقات دائما بنفس العرض، او عند بناء شبكة قد تضاف او تزال منها عناصر ديناميكيا وتريد ان يشعر التخطيط "بالتثبيت."
  • استخدم auto-fit عندما: تريد للعناصر ان تتوسع وتشغل كل المساحة المتاحة. هذا مثالي لاقسام البطل مع عدد متغير من بطاقات الميزات، وعناصر التنقل التي يجب ان تنتشر عبر الراس، او اي سياق تريد فيه ان يبدو المحتوى ممتلئا وسخيا.

مثال: شريط التنقل مع auto-fit

.nav-bar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 8px;
    padding: 12px;
    background: #1a1a2e;
}

.nav-item {
    text-align: center;
    padding: 10px 16px;
    color: white;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 6px;
}

/* سواء كان لديك 4 او 8 عناصر تنقل، ستمتد دائما
   لملء العرض الكامل لشريط التنقل */

مثال: شبكة المنتجات مع auto-fill

.product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 24px;
    padding: 24px;
}

.product-card {
    background: white;
    border-radius: 12px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    overflow: hidden;
}

/* المنتجات تحافظ دائما على احجام بطاقات متسقة.
   اذا كان الصف يتسع لـ 4 بطاقات لكن يوجد 2 فقط،
   المساحة المتبقية تبقى فارغة (لا تمتد). */

معالجة الحالات الحدية مع auto-fill و minmax

هناك بعض الحالات الحدية المهمة التي يجب الانتباه لها عند استخدام نمط auto-fill/minmax:

حالة حدية: الحاوية اضيق من الحد الادنى

/* المشكلة: اذا كانت الحاوية اضيق من 250px،
   العنصر يفيض لانه لا يمكن ان يصغر تحت 250px */
.grid {
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}

/* الحل: استخدم min() لتعيين حد ادنى متجاوب */
.grid {
    grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr));
}

/* الان الحد الادنى هو اما 250px او 100% من الحاوية،
   ايهما اصغر. في حاوية 200px، العمود يصبح 200px (100%)
   بدلا من الفيضان عند 250px. */
تحذير: نمط repeat(auto-fill, minmax(250px, 1fr)) يمكن ان يسبب فيضان افقي على الحاويات الضيقة جدا (مثل شاشات الهاتف مع حشو). فكر دائما في استخدام min(250px, 100%) كحد ادنى لمنع ذلك. النمط repeat(auto-fill, minmax(min(250px, 100%), 1fr)) هو النسخة المضادة للرصاص حقا.

مقدمة الى Subgrid

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

الكلمة المفتاحية subgrid تستخدم كقيمة لـ grid-template-columns و/او grid-template-rows على عنصر شبكة هو نفسه حاوية شبكة. عندما تعين grid-template-columns: subgrid، الشبكة الفرعية تستخدم مسارات اعمدة الشبكة الام للجزء الذي تشغله من الشبكة الام، بدلا من تعريف مساراتها الخاصة.

مثال: القواعد الاساسية لـ Subgrid

.parent-grid {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    gap: 20px;
}

.child-item {
    grid-column: 1 / 4;  /* يمتد عبر كل اعمدة الام الثلاثة */

    display: grid;
    grid-template-columns: subgrid;  /* يرث اعمدة الام الثلاثة */
    /* الابن الان لديه 3 اعمدة تتطابق مع 1fr 2fr 1fr للام */
}

.child-item > .a { grid-column: 1; }  /* يتحاذى مع عمود الام 1 */
.child-item > .b { grid-column: 2; }  /* يتحاذى مع عمود الام 2 */
.child-item > .c { grid-column: 3; }  /* يتحاذى مع عمود الام 3 */
ملاحظة: Subgrid هي قيمة لـ grid-template-columns او grid-template-rows، وليست قيمة عرض جديدة. العنصر الفرعي يجب اولا ان يكون عنصر شبكة (موضوع على الشبكة الام) وايضا حاوية شبكة (display: grid). يربط بين هذين الدورين بوراثة المسارات من الام.

Subgrid لمحاذاة محتوى البطاقات

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

مثال: بطاقات محاذاة مع Subgrid

<div class="card-grid">
    <article class="card">
        <img src="photo1.jpg" alt="صورة 1">
        <h3>عنوان قصير</h3>
        <p>وصف مختصر لهذه البطاقة.</p>
        <a href="#" class="btn">اقرا المزيد</a>
    </article>
    <article class="card">
        <img src="photo2.jpg" alt="صورة 2">
        <h3>عنوان بطاقة اطول بكثير يلتف الى سطرين</h3>
        <p>وصف اطول يحتوي على نص اكثر ويشغل مساحة اكبر.</p>
        <a href="#" class="btn">اقرا المزيد</a>
    </article>
    <article class="card">
        <img src="photo3.jpg" alt="صورة 3">
        <h3>عنوان متوسط هنا</h3>
        <p>وصف متوسط.</p>
        <a href="#" class="btn">اقرا المزيد</a>
    </article>
</div>

CSS: Subgrid لمحاذاة البطاقات

.card-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    /* تعريف 4 مسارات صفوف لاقسام محتوى كل بطاقة */
    grid-template-rows: auto auto auto auto;
    gap: 24px;
}

.card {
    grid-row: span 4;           /* كل بطاقة تمتد 4 صفوف ام */
    display: grid;
    grid-template-rows: subgrid; /* ترث مسارات صفوف الام */
    background: white;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.card img {
    width: 100%;
    height: 200px;
    object-fit: cover;
}

.card h3 {
    padding: 16px 16px 8px;
    margin: 0;
}

.card p {
    padding: 0 16px;
    color: #666;
    margin: 0;
}

.card .btn {
    align-self: end;
    margin: 16px;
    padding: 10px 20px;
    background: #667eea;
    color: white;
    text-decoration: none;
    border-radius: 6px;
    text-align: center;
}

/* النتيجة: كل صور البطاقات تتحاذى، كل العناوين تتحاذى،
   كل الاوصاف تتحاذى، وكل الازرار تتحاذى افقيا
   عبر الصف -- بغض النظر عن اختلاف طول المحتوى! */

هذا يغير قواعد اللعبة لتخطيطات البطاقات. قبل subgrid، تحقيق هذه المحاذاة يتطلب اما ارتفاعات ثابتة (التي تنكسر مع المحتوى الديناميكي)، او JavaScript (الهش والبطيء)، او حلول Flexbox معقدة. Subgrid يحله بانيقية مع CSS نقي.

Subgrid على كلا المحورين

يمكنك تطبيق subgrid على الاعمدة والصفوف في وقت واحد. هذا مفيد عندما يمتد عنصر فرعي عبر عدة اعمدة وعدة صفوف من الشبكة الام ويحتاج لمحاذاة محتواه الداخلي مع مسارات اعمدة وصفوف الام.

مثال: Subgrid على محورين

.parent {
    display: grid;
    grid-template-columns: 200px 1fr 1fr 200px;
    grid-template-rows: auto 1fr auto;
    gap: 16px;
    min-height: 100vh;
}

.featured-section {
    grid-column: 2 / 4;  /* يمتد عبر عمودين وسطيين */
    grid-row: 1 / 4;     /* يمتد عبر كل الصفوف الثلاثة */

    display: grid;
    grid-template-columns: subgrid;  /* يرث عمودي الام */
    grid-template-rows: subgrid;     /* يرث 3 صفوف الام */
    gap: 16px;
}

/* ابناء .featured-section يتحاذون الان بشكل مثالي
   مع مسارات اعمدة وصفوف الشبكة الام */
.featured-section .headline {
    grid-column: 1 / 3;  /* يمتد عبر كلا العمودين الموروثين */
    grid-row: 1;
}

.featured-section .article {
    grid-column: 1;
    grid-row: 2;
}

.featured-section .sidebar-content {
    grid-column: 2;
    grid-row: 2;
}

Subgrid ووراثة الفجوات

عندما يستخدم الابن subgrid، يرث مسارات الام لكن ليس تلقائيا فجوة الام. الشبكة الفرعية تستخدم خاصية gap الخاصة بها. ومع ذلك، مسارات subgrid تحسب بما في ذلك فجوات الام، لذا المحاذاة تبقى محفوظة. يمكنك تعيين فجوة مختلفة على subgrid او حتى تعيينها الى صفر.

مثال: Subgrid مع فجوة مخصصة

.parent {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 24px;  /* فجوة الام */
}

.child {
    grid-column: 1 / 5;
    display: grid;
    grid-template-columns: subgrid;
    gap: 8px;   /* الابن يمكن ان يكون له فجوته الخاصة */
    /* مسارات الاعمدة تبقى متحاذاة مع الام، لكن الفجوات
       بين عناصر الابن هي 8px بدلا من 24px */
}

Subgrid عملي: تخطيط نموذج

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

مثال: نموذج محاذى مع Subgrid

<form class="form-grid">
    <div class="form-row">
        <label for="name">الاسم الكامل</label>
        <input type="text" id="name">
        <span class="hint">مطلوب</span>
    </div>
    <div class="form-row">
        <label for="email">البريد الالكتروني</label>
        <input type="email" id="email">
        <span class="hint">لن نشارك بريدك ابدا</span>
    </div>
    <div class="form-row">
        <label for="phone">الهاتف</label>
        <input type="tel" id="phone">
        <span class="hint">اختياري</span>
    </div>
</form>

CSS: Subgrid للنموذج

.form-grid {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 16px 24px;
    max-width: 600px;
}

.form-row {
    grid-column: 1 / -1;       /* يمتد عبر كل الاعمدة الثلاثة */
    display: grid;
    grid-template-columns: subgrid;  /* يرث اعمدة الام */
    align-items: center;
}

.form-row label {
    font-weight: 600;
    white-space: nowrap;
}

.form-row input {
    padding: 8px 12px;
    border: 1px solid #ddd;
    border-radius: 6px;
}

.form-row .hint {
    font-size: 0.85rem;
    color: #888;
}

/* كل التسميات تتحاذى في العمود الاول (بحجم تلقائي للاعرض).
   كل المدخلات تتحاذى في العمود الثاني (مرن).
   كل التلميحات تتحاذى في العمود الثالث. */

انماط تخطيط الحجارة (Masonry)

تخطيط الحجارة (مثل Pinterest) يحتوي على عناصر بارتفاعات متفاوتة تتراص باحكام بدون فجوات، تملا عموديا حيث تتوفر المساحة. بينما CSS لا تملك قيمة masonry اصلية في مواصفات الشبكة المستقرة بعد، هناك قيمة تجريبية grid-template-rows: masonry قيد التطوير. في الوقت الحالي، يمكنك تقريب تاثيرات الحجارة باستخدام الشبكة وبعض التقنيات الابداعية.

مثال: تقريب Masonry مع الشبكة

.masonry-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    grid-auto-rows: 10px;  /* ارتفاع صف صغير للتحكم الدقيق */
    gap: 16px;
}

/* كل عنصر يمتد عبر عدد مختلف من الصفوف بناء على ارتفاع المحتوى */
.masonry-item.short  { grid-row: span 20; }  /* ~200px */
.masonry-item.medium { grid-row: span 30; }  /* ~300px */
.masonry-item.tall   { grid-row: span 45; }  /* ~450px */

.masonry-item {
    background: white;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.masonry-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
ملاحظة: تخطيط masonry الاصلي في CSS (باستخدام grid-template-rows: masonry) يجري تنفيذه حاليا بواسطة مصنعي المتصفحات. Firefox لديه دعم تجريبي خلف علم. عندما يصبح مدعوما على نطاق واسع، ستتمكن من تحقيق تخطيطات masonry مثالية بخاصية CSS واحدة. حتى ذلك الحين، تقنية امتداد grid-auto-rows المعروضة اعلاه هي افضل تقريب بـ CSS نقي. لتخطيطات masonry في الانتاج، مكتبات JavaScript مثل Masonry.js تبقى الحل الاكثر موثوقية.

مثال: صيغة Masonry الاصلية المستقبلية

/* تجريبي -- ليس مدعوما على نطاق واسع بعد */
.masonry-native {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    grid-template-rows: masonry;  /* العناصر تتراص عموديا! */
    gap: 16px;
}

/* مع هذا، العناصر تملا الفجوات العمودية تلقائيا
   بدون الحاجة لتحديد امتدادات الصفوف يدويا. */

انماط متجاوبة معقدة بدون استعلامات وسائط

بالجمع بين auto-fill و minmax() و clamp() ومتغيرات CSS المخصصة، يمكنك انشاء انماط متجاوبة متطورة لا تتطلب اي استعلامات وسائط. هذه الانماط اكثر سيولة من التصميمات القائمة على نقاط التوقف لانها تتكيف باستمرار بدلا من القفز بين حالات ثابتة.

مثال: شبكة بطاقات سائلة بالكامل مع متغيرات مخصصة

:root {
    --card-min: 280px;
    --card-gap: 24px;
}

.fluid-grid {
    display: grid;
    grid-template-columns: repeat(
        auto-fill,
        minmax(min(var(--card-min), 100%), 1fr)
    );
    gap: var(--card-gap);
    padding: var(--card-gap);
}

/* تغيير الحد الادنى لعرض البطاقة لاقسام مختلفة */
.fluid-grid.narrow-cards {
    --card-min: 200px;
}

.fluid-grid.wide-cards {
    --card-min: 400px;
}

مثال: تخطيط شريط جانبي متجاوب بدون استعلامات وسائط

.sidebar-layout {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
    gap: 32px;
}

.sidebar-layout .main-content {
    min-width: 0;  /* منع الفيضان من المحتوى العريض */
}

.sidebar-layout .sidebar {
    min-width: 0;
}

/* عندما تكون الحاوية واسعة بما يكفي، ينشئ عمودين او اكثر.
   عندما تكون ضيقة، كل شيء يتكدس في عمود واحد.
   احجام الشريط الجانبي والمحتوى الرئيسي تحدد بواسطة
   مزيج auto-fit + minmax تلقائيا. */

مثال: تنويعات نمط RAM (Repeat, Auto, Minmax)

/* عناصر صغيرة: اعمدة كثيرة على الشاشات العريضة */
.icons-grid {
    grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
}

/* عناصر متوسطة: شبكة بطاقات قياسية */
.card-grid {
    grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
}

/* عناصر كبيرة: اعمدة اقل، عناصر تشغل مساحة اكبر */
.feature-grid {
    grid-template-columns: repeat(auto-fill, minmax(min(500px, 100%), 1fr));
}

/* غير متماثل: حد ادنى مختلف للعمود الاول */
.asymmetric {
    grid-template-columns: minmax(200px, 1fr) repeat(auto-fill, minmax(300px, 2fr));
}

الشبكة مع aspect-ratio

خاصية aspect-ratio في CSS تتناسب بشكل جميل مع تخطيطات الشبكة، خاصة لمعارض الصور وشبكات الوسائط. عندما تعين نسبة عرض الى ارتفاع على عناصر الشبكة، تحافظ على تناسبها عند تغيير حجم اعمدة الشبكة، مما ينشئ تخطيطات متسقة بصريا بدون تحديد ارتفاعات ثابتة.

مثال: معرض صور مع نسبة العرض الى الارتفاع

.image-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 12px;
}

.gallery-item {
    aspect-ratio: 1 / 1;  /* مربعات مثالية */
    overflow: hidden;
    border-radius: 8px;
}

.gallery-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.3s ease;
}

.gallery-item:hover img {
    transform: scale(1.05);
}

مثال: شبكة فيديو بنسبة 16:9

.video-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
    gap: 20px;
}

.video-thumbnail {
    aspect-ratio: 16 / 9;
    background: #000;
    border-radius: 12px;
    overflow: hidden;
    position: relative;
}

.video-thumbnail img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.play-button {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 60px;
    height: 60px;
    background: rgba(255, 255, 255, 0.9);
    border-radius: 50%;
}

مثال: نسب عرض الى ارتفاع مختلطة في شبكة

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

.media-item.landscape { aspect-ratio: 16 / 9; }
.media-item.portrait  { aspect-ratio: 3 / 4;
                        grid-row: span 2; }
.media-item.square    { aspect-ratio: 1 / 1; }

.media-item {
    overflow: hidden;
    border-radius: 8px;
    background: #f0f0f0;
}

.media-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

اعتبارات الاداء

فهم تاثيرات الاداء لميزات الشبكة المتقدمة يساعدك في اتخاذ قرارات مستنيرة:

  • auto-fill و auto-fit: لهما تاثير اداء ضئيل. خوارزمية شبكة المتصفح تتعامل مع حساب المسارات بكفاءة، حتى مع عناصر كثيرة. ومع ذلك، مئات عناصر الشبكة في صفحة واحدة يمكن ان تسبب مشاكل اداء تخطيط -- فكر في التمرير الافتراضي للقوائم الطويلة جدا.
  • Subgrid: يضيف تبعية بين حسابات تخطيط الام والابن. الام يجب ان تحسب مساراتها قبل ان يتمكن الابن من استخدامها. لتخطيطات الصفحات النموذجية (2-3 مستويات تداخل)، هذا غير محسوس. الشبكات الفرعية المتداخلة بعمق (5+ مستويات) قد تؤثر نظريا على الاداء، رغم ان هذا نمط غير معتاد.
  • minmax() مع حسابات معقدة: استخدام minmax() مع calc() او min() او max() او clamp() لا يؤثر بشكل كبير على الاداء. هذه الحسابات تحل مرة واحدة خلال مرحلة التخطيط.
  • اداء تغيير الحجم: شبكات auto-fill/auto-fit تعيد حساب عدد الاعمدة عند كل تغيير حجم حاوية. المتصفح محسن لهذا، لكن دمجه مع محتوى ثقيل (صور كبيرة، تخطيطات متداخلة معقدة) قد يبدو بطيئا على الاجهزة منخفضة المستوى. استخدم content-visibility: auto للعناصر خارج الشاشة لتحسين اداء التمرير.

مثال عملي: معرض اعمال متجاوب كامل

لنجمع كل شيء من هذا الدرس في صفحة معرض اعمال كاملة ومتجاوبة لا تستخدم اي استعلامات وسائط لتخطيطات شبكتها.

HTML: بنية معرض الاعمال

<div class="portfolio">
    <section class="hero-section">
        <h1>معرض اعمالي</h1>
        <p>مطور ويب ومصمم</p>
    </section>

    <section class="skills-section">
        <div class="skill-card">HTML</div>
        <div class="skill-card">CSS</div>
        <div class="skill-card">JavaScript</div>
        <div class="skill-card">React</div>
        <div class="skill-card">Node.js</div>
        <div class="skill-card">Python</div>
    </section>

    <section class="projects-section">
        <article class="project-card">
            <img src="project1.jpg" alt="مشروع 1">
            <h3>منصة تجارة الكترونية</h3>
            <p>متجر الكتروني متكامل</p>
            <a href="#">عرض المشروع</a>
        </article>
        <!-- المزيد من بطاقات المشاريع... -->
    </section>

    <section class="contact-section">
        <form class="contact-form">
            <div class="form-row">
                <label>الاسم</label>
                <input type="text">
            </div>
            <div class="form-row">
                <label>البريد الالكتروني</label>
                <input type="email">
            </div>
            <div class="form-row">
                <label>الرسالة</label>
                <textarea></textarea>
            </div>
        </form>
    </section>
</div>

CSS: معرض اعمال متجاوب كامل

/* المهارات: auto-fit لملء المساحة المتاحة */
.skills-section {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
    gap: 16px;
    padding: 40px 24px;
}

.skill-card {
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    padding: 24px;
    border-radius: 12px;
    text-align: center;
    font-weight: 700;
    font-size: 1.1rem;
}

/* المشاريع: auto-fill لاحجام بطاقات متسقة */
.projects-section {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
    /* صفوف subgrid لمحتوى بطاقات محاذى */
    grid-template-rows: repeat(auto-fill, auto auto auto auto);
    gap: 24px;
    padding: 40px 24px;
}

.project-card {
    grid-row: span 4;
    display: grid;
    grid-template-rows: subgrid;
    background: white;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.project-card img {
    aspect-ratio: 16 / 9;
    width: 100%;
    object-fit: cover;
}

.project-card h3 {
    padding: 16px 20px 0;
    margin: 0;
}

.project-card p {
    padding: 8px 20px;
    color: #666;
    margin: 0;
}

.project-card a {
    align-self: end;
    margin: 0 20px 20px;
    padding: 10px;
    background: #667eea;
    color: white;
    text-align: center;
    border-radius: 8px;
    text-decoration: none;
}

/* نموذج الاتصال: subgrid لمحاذاة التسميات */
.contact-form {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 16px 24px;
    max-width: 500px;
    margin: 0 auto;
    padding: 40px 24px;
}

.form-row {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
    align-items: start;
}

/* صفر استعلامات وسائط -- متجاوب بالكامل! */

دعم المتصفحات والتحسين التدريجي

قبل استخدام هذه الميزات في الانتاج، افهم دعم المتصفحات:

  • auto-fill و auto-fit: مدعوم في كل المتصفحات الحديثة منذ 2017. امن للاستخدام في الانتاج بدون بدائل.
  • Subgrid: مدعوم في Firefox (منذ الاصدار 71)، Chrome (منذ الاصدار 117)، Safari (منذ الاصدار 16)، و Edge (منذ الاصدار 117). للمتصفحات الاقدم، قدم بديلا بدون subgrid باستخدام @supports.
  • تخطيط Masonry: مدعوم تجريبيا فقط في Firefox خلف علم. ليس جاهزا للانتاج. استخدم حلول JavaScript لـ masonry عبر المتصفحات.
  • aspect-ratio: مدعوم في كل المتصفحات الحديثة منذ 2021. امن للاستخدام مع بديل قائم على الحشو للمتصفحات القديمة جدا.

مثال: التحسين التدريجي لـ Subgrid

/* تخطيط اساسي بدون subgrid */
.card {
    display: grid;
    grid-template-rows: auto auto 1fr auto;
}

/* تخطيط محسن مع subgrid عند الدعم */
@supports (grid-template-rows: subgrid) {
    .card-grid {
        grid-template-rows: repeat(auto-fill, auto auto auto auto);
    }

    .card {
        grid-row: span 4;
        grid-template-rows: subgrid;
    }
}
نصيحة: استخدم قاعدة @supports لتحسين تخطيطاتك تدريجيا مع subgrid. التخطيط الاساسي يجب ان يعمل جيدا بدون subgrid (باستخدام صفوف شبكة عادية)، ثم subgrid يضيف تحسين المحاذاة للمتصفحات التي تدعمه. هذا يضمن تجربة جيدة لكل المستخدمين مع الاستفادة من افضل الميزات للمتصفحات الحديثة.

تمرين عملي

التمرين 1: ابني معرض صور متجاوب باستخدام repeat(auto-fill, minmax(min(200px, 100%), 1fr)). اضف 12 صورة مع aspect-ratio: 1/1 للمربعات. اختبره بتغيير حجم نافذة المتصفح من ضيق جدا (300px) الى واسع جدا (1400px) ولاحظ كيف تضاف وتزال الاعمدة تلقائيا بدون اي استعلامات وسائط.

التمرين 2: انشئ مقارنة بين auto-fill و auto-fit. ابني شبكتين متطابقتين جنبا الى جنب، كل منهما بـ 3 عناصر بطاقات فقط، في حاوية واسعة (1200px). استخدم auto-fill للشبكة الاولى و auto-fit للثانية. عين الحد الادنى لعرض البطاقة الى 200px. لاحظ ووثق الفرق البصري بين كيفية تعامل الشبكتين مع المساحة الاضافية.

التمرين 3: ابني شبكة بطاقات بـ 6 بطاقات باستخدام subgrid لمحاذاة محتوى البطاقات. كل بطاقة يجب ان تحتوي على صورة، وعنوان، ووصف (باطوال متفاوتة)، وزر. استخدم grid-template-rows: subgrid على البطاقات بحيث تتحاذى العناوين والاوصاف والازرار افقيا عبر كل البطاقات في نفس الصف. استخدم @supports لتوفير بديل للمتصفحات بدون دعم subgrid.

التمرين 4: انشئ تخطيط صفحة كامل متجاوب لا يستخدم اي استعلامات وسائط. استخدم auto-fill او auto-fit مع minmax() لكل اقسام الشبكة. الصفحة يجب ان تتضمن قسم بطل، وشبكة مهارات/ايقونات، وشبكة مشاريع، وقسم شهادات، وتذييل. كل قسم يجب ان يتكيف بسلاسة من عرض حاوية 320px الى 1920px.