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

محددات الدمج: السلالة والفرع والشقيق

25 دقيقة الدرس 4 من 60

ما هي محددات الدمج؟

في CSS، محدد الدمج هو حرف او رمز يحدد العلاقة بين محددين. بينما المحددات البسيطة (مثل .class و #id او element) تستهدف العناصر مباشرة، تتيح لك محددات الدمج استهداف العناصر بناء على موضعها بالنسبة للعناصر الاخرى في شجرة مستند HTML. هذه واحدة من اقوى ميزات CSS لأنها تسمح لك بتنسيق العناصر بناء على سياقها -- اين تقع في تسلسل DOM -- دون اضافة فئات اضافية الى الترميز الخاص بك.

يوفر CSS اربعة محددات دمج، كل منها يمثل نوعا مختلفا من العلاقات:

  1. محدد السلالة (مسافة) -- يحدد العناصر المتداخلة على اي عمق داخل عنصر سلف.
  2. محدد الفرع (>) -- يحدد فقط العناصر الفرعية المباشرة للعنصر الاصل.
  3. محدد الشقيق المجاور (+) -- يحدد العنصر الذي يلي الشقيق مباشرة.
  4. محدد الشقيق العام (~) -- يحدد جميع الاشقاء التالين.

فهم محددات الدمج هذه امر اساسي لكتابة CSS فعالة وقابلة للصيانة. فهي تقلل الحاجة لأسماء فئات مفرطة وتتيح لك الاستفادة من البنية الطبيعية لـ HTML لتطبيق الانماط بدقة حيث تحتاجها.

ملاحظة: تعمل محددات الدمج عن طريق الجمع بين محددين بسيطين او اكثر. المحدد على الجانب الايسر يحدد السياق (نقطة المرجع)، والمحدد على الجانب الايمن يحدد العنصر (العناصر) الذي سيتم تنسيقه فعليا. على سبيل المثال، في nav a، يكون nav هو السياق و a هو الهدف الذي يتم تنسيقه.

محدد السلالة (مسافة)

يُمثل محدد السلالة بـ مسافة واحدة بين محددين. يطابق العناصر المتداخلة داخل المحدد الاول على اي عمق -- سواء كانت عناصر فرعية مباشرة او احفاد او احفاد احفاد او حتى اعمق. هذا هو محدد الدمج الاكثر استخداما في CSS والاول الذي يتعلمه معظم المطورين.

الصيغة العامة هي:

صيغة محدد السلالة

ancestor descendant {
    property: value;
}

/* هذا يحدد جميع عناصر <a> داخل <nav>، بغض النظر عن العمق */
nav a {
    color: white;
    text-decoration: none;
}

فكر في بنية HTML هذه:

مثال على بنية HTML

<nav class="main-nav">
    <a href="/">الرئيسية</a>
    <div class="dropdown">
        <a href="/about">من نحن</a>
        <ul class="submenu">
            <li>
                <a href="/team">الفريق</a>
            </li>
            <li>
                <a href="/history">التاريخ</a>
            </li>
        </ul>
    </div>
</nav>

المحدد .main-nav a سيطابق جميع الروابط الاربعة: "الرئيسية" (عنصر فرعي مباشر)، و"من نحن" (حفيد عبر div القائمة المنسدلة)، و"الفريق" و"التاريخ" (متداخلة بعمق داخل القائمة الفرعية). محدد السلالة لا يهتم بعدد مستويات التداخل الموجودة بين السلف والهدف.

امثلة عملية لمحدد السلالة

مثال: تنسيق روابط التنقل المتداخلة

/* جميع الروابط داخل الرأس */
header a {
    color: #ecf0f1;
    font-weight: 500;
    transition: color 0.3s ease;
}

header a:hover {
    color: #3498db;
}

/* جميع الفقرات داخل مقال */
article p {
    line-height: 1.8;
    margin-bottom: 1.2em;
    color: #333;
}

/* جميع عناصر القائمة داخل الشريط الجانبي */
.sidebar ul li {
    padding: 8px 12px;
    border-bottom: 1px solid #eee;
}

/* جميع الصور داخل figure ضمن مقال */
article figure img {
    width: 100%;
    height: auto;
    border-radius: 8px;
}

مستويات متعددة من تحديد السلالة

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

مثال: محددات سلالة متعددة المستويات

/* الفقرات داخل جسم البطاقة داخل البطاقة داخل المحتوى الرئيسي */
.main-content .card .card-body p {
    font-size: 0.95rem;
    color: #555;
}

/* الروابط داخل عناصر القائمة داخل قائمة غير مرتبة داخل التذييل */
footer ul li a {
    color: #bdc3c7;
    text-decoration: none;
}

footer ul li a:hover {
    color: #fff;
    text-decoration: underline;
}
خطأ شائع: تجنب محددات السلالة العميقة جدا مثل body div.wrapper main section article div.content p span.highlight. هذا هش (اي اعادة هيكلة HTML تكسره)، ومحدد بشكل مفرط (صعب التجاوز)، وابطأ للمتصفح في المطابقة. استهدف 3 مستويات كحد اقصى من التداخل في معظم الحالات. إذا كنت بحاجة لاستهداف اعمق، فكر في اضافة فئة وصفية للعنصر بدلا من ذلك.

تأثيرات الاداء لمحددات السلالة

تقيم المتصفحات محددات CSS من اليمين الى اليسار. عندما يواجه المتصفح nav a، يجد اولا كل عنصر <a> في الصفحة، ثم يتحقق من كل واحد لمعرفة ما إذا كان لديه سلف <nav>. في الصفحات التي تحتوي على مئات الروابط، قد يكون هذا اقل كفاءة من استخدام فئة مثل .nav-link. في معظم الحالات يكون فرق الاداء ضئيلا، لكنه يصبح مهما في التطبيقات الحساسة للاداء او الصفحات ذات DOM كبير جدا.

نصيحة احترافية: إذا كان الاداء مصدر قلق (مثلا في تطبيق ويب كبير يحتوي على آلاف عناصر DOM)، فضل المحددات القائمة على الفئات على محددات السلالة العميقة. محدد مثل .nav-link اسرع بكثير من header nav ul li a لأن المتصفح يحتاج فقط للتحقق من شرط واحد بدلا من التنقل عبر عدة اسلاف.

محدد الفرع (>)

محدد الفرع، المكتوب كـ >، يحدد فقط العناصر الفرعية المباشرة لعنصر ما. على عكس محدد السلالة، لا يصل الى مستويات اعمق من التداخل. يجب ان يكون العنصر الهدف فرعا مباشرا للأصل -- لا احفاد ولا عناصر متداخلة بعمق.

صيغة محدد الفرع

parent > child {
    property: value;
}

/* فقط عناصر <li> الفرعية المباشرة لـ .menu، وليس عناصر القائمة الفرعية المتداخلة */
.menu > li {
    display: inline-block;
    padding: 10px 20px;
}

هذا التمييز بين محدد السلالة ومحدد الفرع امر بالغ الاهمية. فكر في HTML هذا:

فهم الفرق

<ul class="menu">
    <li>الرئيسية</li>              <!-- فرع مباشر: مُحدد بواسطة .menu > li -->
    <li>المنتجات
        <ul class="submenu">
            <li>اجهزة محمولة</li>   <!-- ليس فرعا مباشرا: غير مُحدد -->
            <li>هواتف</li>          <!-- ليس فرعا مباشرا: غير مُحدد -->
        </ul>
    </li>
    <li>اتصل بنا</li>              <!-- فرع مباشر: مُحدد بواسطة .menu > li -->
</ul>

/* CSS */
/* السلالة: يحدد جميع عناصر li (5 اجمالا) */
.menu li {
    color: blue;
}

/* الفرع: يحدد فقط العناصر الفرعية المباشرة الثلاثة */
.menu > li {
    color: red;
    font-weight: bold;
}

امثلة عملية لمحدد الفرع

مثال: تنسيق التنقل مع القوائم المنسدلة المتداخلة

/* تنسيق فقط روابط التنقل ذات المستوى الاعلى، وليس روابط القائمة المنسدلة */
.navbar > a {
    font-size: 1rem;
    font-weight: 600;
    padding: 12px 16px;
    color: #2c3e50;
    text-decoration: none;
}

/* روابط القائمة المنسدلة تحصل على تنسيق مختلف */
.dropdown-menu > a {
    font-size: 0.9rem;
    font-weight: 400;
    padding: 8px 16px;
    color: #555;
    display: block;
}

/* فقط العناصر الفرعية المباشرة لحاوية الشبكة تحصل على تنسيق الشبكة */
.grid-container > div {
    padding: 20px;
    background-color: #f8f9fa;
    border-radius: 8px;
}

/* ازالة الهامش من آخر فقرة فرعية مباشرة فقط */
.card-body > p:last-child {
    margin-bottom: 0;
}

مثال: قائمة تنقل متعددة المستويات

/* عناصر القائمة ذات المستوى الاعلى افقية */
.nav-menu > li {
    display: inline-block;
    position: relative;
}

/* عناصر المستوى الثاني عمودية (منسدلة) */
.nav-menu > li > ul > li {
    display: block;
    width: 200px;
}

/* عناصر المستوى الثالث (قوائم منبثقة) */
.nav-menu > li > ul > li > ul > li {
    display: block;
    width: 180px;
}

/* روابط فرعية مباشرة لعناصر المستوى الاعلى */
.nav-menu > li > a {
    padding: 15px 20px;
    font-weight: 600;
    text-transform: uppercase;
}

/* روابط فرعية مباشرة لعناصر القائمة المنسدلة */
.nav-menu > li > ul > li > a {
    padding: 10px 16px;
    font-weight: 400;
    font-size: 0.9rem;
}
نصيحة احترافية: محدد الفرع مفيد بشكل خاص عند العمل مع CSS المبني على المكونات حيث تريد تنسيق البنية المباشرة للمكون فقط دون التأثير عرضيا على المكونات الفرعية المتداخلة. على سبيل المثال، .card > .card-header يضمن انك تنسق فقط رأس البطاقة الخاصة بها، وليس رأسا داخل بطاقة متداخلة.

استخدام محدد الفرع مع المحدد الشامل

الجمع بين محدد الفرع والمحدد الشامل (*) يتيح لك استهداف جميع العناصر الفرعية المباشرة لعنصر بغض النظر عن نوعها. هذا نمط قوي للتخطيط والمسافات.

مثال: توزيع المسافات بين جميع العناصر الفرعية المباشرة

/* اضافة مسافات عمودية بين جميع العناصر الفرعية المباشرة لقسم */
.content-section > * {
    margin-bottom: 1.5rem;
}

/* ازالة الهامش من آخر عنصر فرعي مباشر */
.content-section > *:last-child {
    margin-bottom: 0;
}

/* محدد "بومة المفصولة الدماغ" -- مسافة بين الاشقاء المتجاورين */
.stack > * + * {
    margin-top: 1.5rem;
}

/* اعادة تعيين جميع العناصر الفرعية المباشرة بدون حشو */
.reset-container > * {
    padding: 0;
    margin: 0;
}

محدد الشقيق المجاور (+)

محدد الشقيق المجاور، المكتوب كـ +، يحدد عنصرا يكون الشقيق التالي مباشرة لعنصر آخر. يجب ان يشترك كلا العنصرين في نفس الاصل، ويجب ان يأتي الهدف مباشرة بعد العنصر المرجعي بدون اي عناصر اخرى بينهما.

صيغة محدد الشقيق المجاور

element1 + element2 {
    property: value;
}

/* حدد الفقرة التي تأتي مباشرة بعد h2 */
h2 + p {
    font-size: 1.1rem;
    color: #555;
    margin-top: 0.5rem;
}

فكر في HTML هذا:

فهم الاشقاء المجاورين

<article>
    <h2>المقدمة</h2>
    <p>هذه الفقرة مُحددة بواسطة h2 + p</p>
    <p>هذه الفقرة غير مُحددة (ليست مباشرة بعد h2)</p>
    <h2>التفاصيل</h2>
    <p>هذه الفقرة مُحددة (مباشرة بعد h2)</p>
    <ul>
        <li>عنصر</li>
    </ul>
    <p>هذه الفقرة غير مُحددة (مسبوقة بـ ul وليس h2)</p>
</article>

امثلة عملية لمحدد الشقيق المجاور

مثال: الطباعة وتدفق المحتوى

/* تنسيق اول فقرة بعد كل عنوان */
h1 + p,
h2 + p,
h3 + p {
    font-size: 1.1em;
    color: #666;
    line-height: 1.9;
}

/* تقليل الهامش العلوي عندما يتبع عنوان عنوانا آخر */
h2 + h3 {
    margin-top: 0.5rem;
}

/* اضافة مسافة اضافية بعد الصور */
img + p {
    margin-top: 2rem;
}

/* تنسيق تعليق يأتي مباشرة بعد شكل */
figure + figcaption {
    font-style: italic;
    color: #888;
    font-size: 0.9em;
    margin-top: 0.5rem;
}

مثال: ازواج التسمية وحقل الادخال في النماذج

/* تنسيق حقول الادخال التي تأتي مباشرة بعد التسميات */
label + input,
label + select,
label + textarea {
    margin-top: 4px;
    display: block;
    width: 100%;
    padding: 10px 12px;
    border: 1px solid #ddd;
    border-radius: 6px;
}

/* تنسيق رسائل الخطأ التي تظهر مباشرة بعد حقول الادخال غير الصالحة */
input.error + .error-message {
    display: block;
    color: #e74c3c;
    font-size: 0.85rem;
    margin-top: 4px;
}

/* تنسيق نص التلميح بعد حقل الادخال */
input + .hint {
    color: #95a5a6;
    font-size: 0.8rem;
    margin-top: 2px;
}

مثال: محدد بومة المفصولة الدماغ

/* احد اشهر استخدامات محدد الشقيق المجاور.
   يضيف هامشا علويا لكل عنصر يتبع عنصرا آخر.
   النتيجة: مسافات متساوية بين الاشقاء بدون هامش على العنصر الاول. */

.flow > * + * {
    margin-top: 1.5em;
}

/* هذا يعادل كتابة:
   .flow > *:not(:first-child) { margin-top: 1.5em; }
   لكن محدد "البومة" (المسمى بسبب شكله: * + *) هو
   نمط CSS معروف. */

/* تنويع: مسافات مختلفة لأنواع عناصر مختلفة */
.article-content > * + * {
    margin-top: 1rem;
}

.article-content > * + h2 {
    margin-top: 3rem;
}

.article-content > * + h3 {
    margin-top: 2rem;
}
ملاحظة: محدد الشقيق المجاور ينظر فقط للأمام في DOM. لا يوجد محدد CSS لتنسيق شقيق سابق. المحدد A + B يعني "B الذي يسبقه A مباشرة"، وليس "A الذي يتبعه B مباشرة." يُطبق التنسيق دائما على العنصر الموجود على الجانب الايمن من +.

محدد الشقيق العام (~)

محدد الشقيق العام، المكتوب كـ ~، يحدد جميع الاشقاء الذين يأتون بعد العنصر المرجعي. على عكس محدد الشقيق المجاور (+)، لا تحتاج العناصر الهدف ان تكون تالية مباشرة -- يمكن ان يكون بينها اي عدد من العناصر الاخرى، طالما انها تشترك في نفس الاصل وتأتي بعد العنصر المرجعي في ترتيب المصدر.

صيغة محدد الشقيق العام

element1 ~ element2 {
    property: value;
}

/* حدد جميع الفقرات التي تأتي بعد h2، وليس الاولى فقط */
h2 ~ p {
    color: #333;
    line-height: 1.8;
}

لنقارن بين محدد الشقيق المجاور والشقيق العام:

المقارنة بين محدد الشقيق المجاور والعام

<div class="container">
    <h2>العنوان</h2>
    <p>الفقرة 1</p>    <!-- h2 + p: نعم  |  h2 ~ p: نعم -->
    <span>عنصر span</span>
    <p>الفقرة 2</p>    <!-- h2 + p: لا   |  h2 ~ p: نعم -->
    <div>عنصر div</div>
    <p>الفقرة 3</p>    <!-- h2 + p: لا   |  h2 ~ p: نعم -->
</div>

/* CSS */
/* المجاور: يحدد الفقرة 1 فقط */
h2 + p {
    font-weight: bold;
}

/* العام: يحدد الفقرات 1 و 2 و 3 */
h2 ~ p {
    color: #2c3e50;
}

امثلة عملية لمحدد الشقيق العام

مثال: تنسيق قسم المحتوى

/* تنسيق جميع الفقرات التي تتبع عنوانا في المقال */
.article-body h2 ~ p {
    padding-left: 1rem;
    border-left: 3px solid #3498db;
}

/* جميع عناصر القائمة بعد العنصر "النشط" تصبح باهتة */
.step-list li.active ~ li {
    opacity: 0.5;
    color: #95a5a6;
}

/* جميع البطاقات بعد البطاقة المميزة تصبح اصغر */
.card-grid .featured ~ .card {
    transform: scale(0.95);
}

مثال: انماط تفاعلية بـ CSS فقط

/* اكورديون بـ CSS فقط باستخدام خدعة مربع الاختيار + الشقيق العام */
.accordion-toggle {
    display: none;
}

.accordion-toggle:checked ~ .accordion-content {
    max-height: 500px;
    opacity: 1;
    padding: 16px;
}

.accordion-toggle:checked ~ .accordion-label::after {
    transform: rotate(180deg);
}

/* تبديل التنقل للهاتف بـ CSS فقط */
#nav-toggle:checked ~ .nav-menu {
    display: flex;
    transform: translateX(0);
}

#nav-toggle:checked ~ .nav-overlay {
    display: block;
    opacity: 1;
}

/* نظام تقييم بالنجوم */
.star-rating input:checked ~ label {
    color: #f39c12;
}
نصيحة احترافية: محدد الشقيق العام هو العمود الفقري للعديد من الانماط التفاعلية بـ CSS فقط. "خدعة مربع الاختيار" -- حيث تخفي مربع اختيار وتستخدم حالة :checked مع ~ لتبديل رؤية العناصر الشقيقة -- هي تقنية كلاسيكية لإنشاء اكورديونات وتبويبات ومفاتيح تبديل وقوائم هاتف بدون JavaScript.

الجمع بين محددات الدمج للتحديدات المعقدة

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

مثال: الجمع بين عدة محددات دمج

/* العناصر الفرعية المباشرة لـ nav وهي عناصر <li>،
   ثم حدد روابط الارتباط بداخلها (على اي عمق) */
.main-nav > li a {
    color: #2c3e50;
    text-decoration: none;
}

/* الفقرة مباشرة بعد اول عنوان فرعي مباشر h2 للمقال */
article > h2:first-of-type + p {
    font-size: 1.15em;
    font-weight: 500;
    color: #34495e;
}

/* جميع الفقرات التي تتبع صورة داخل figure فرعي مباشر للمقال */
article > figure img ~ p {
    font-style: italic;
    font-size: 0.9em;
}

/* عناصر القائمة الفرعية المباشرة لـ .sidebar nav ul */
.sidebar > nav > ul > li {
    padding: 12px 0;
    border-bottom: 1px solid #eee;
}

/* العنصر بعد العنصر النشط في العناصر الفرعية المباشرة لقائمة الخطوات */
.steps > .active + .step {
    border-left-color: #3498db;
}

مثال: تخطيط البطاقات مع محددات معقدة

/* تخطيط شبكة البطاقات */
.card-grid > .card {
    padding: 24px;
    border: 1px solid #e0e0e0;
    border-radius: 12px;
}

/* صورة البطاقة متبوعة بجسم البطاقة */
.card > .card-image + .card-body {
    padding-top: 16px;
}

/* جميع الفقرات بعد الفقرة الاولى في جسم البطاقة */
.card > .card-body > p ~ p {
    margin-top: 0.75rem;
    color: #666;
}

/* شريط الاجراءات الفرعي المباشر للبطاقة، بعد الجسم */
.card > .card-body ~ .card-actions {
    margin-top: auto;
    padding-top: 16px;
    border-top: 1px solid #eee;
}

/* الروابط داخل منطقة اجراءات البطاقة */
.card > .card-actions > a {
    font-weight: 600;
    color: #3498db;
}

حالات استخدام واقعية

حالة الاستخدام 1: طباعة منشور المدونة

نظام طباعي كامل لمحتوى المدونة باستخدام محددات الدمج للتحكم في المسافات والتسلسل البصري:

مثال: نظام طباعة المدونة

.blog-post > * + * {
    margin-top: 1.5rem;
}

/* العناوين تحتاج مسافة اكبر فوقها */
.blog-post > * + h2 {
    margin-top: 3rem;
}

.blog-post > * + h3 {
    margin-top: 2.5rem;
}

/* مسافة اقل عندما يتبع عنوان فرعي عنوانا */
.blog-post > h2 + h3 {
    margin-top: 1rem;
}

/* الفقرة الرئيسية بعد العنوان */
.blog-post > h1 + p {
    font-size: 1.25rem;
    color: #555;
    line-height: 1.9;
}

/* الاقتباسات بعد الفقرات تحصل على مسافة اضافية */
.blog-post > p + blockquote {
    margin-top: 2rem;
    margin-bottom: 2rem;
}

/* كتل الشفرة بعد الفقرات */
.blog-post > p + pre {
    margin-top: 1.5rem;
}

/* عناصر القائمة التي تتبع عناصر قائمة اخرى */
.blog-post li + li {
    margin-top: 0.5rem;
}

حالة الاستخدام 2: تخطيط النموذج

مثال: تنسيق النموذج باستخدام محددات الدمج

/* مسافة بين مجموعات النموذج */
.form > .form-group + .form-group {
    margin-top: 1.5rem;
}

/* التسميات الفرعية المباشرة لمجموعات النموذج */
.form-group > label {
    display: block;
    font-weight: 600;
    margin-bottom: 0.5rem;
    color: #2c3e50;
}

/* الادخال/التحديد/منطقة النص مباشرة بعد تسمية */
.form-group > label + input,
.form-group > label + select,
.form-group > label + textarea {
    width: 100%;
    padding: 10px 14px;
    border: 2px solid #ddd;
    border-radius: 8px;
    transition: border-color 0.3s ease;
}

/* نص المساعدة بعد اي عنصر ادخال */
.form-group > input ~ .help-text,
.form-group > select ~ .help-text {
    font-size: 0.85rem;
    color: #888;
    margin-top: 4px;
}

/* رسالة الخطأ مباشرة بعد حقل الادخال */
.form-group > input + .error-msg {
    color: #e74c3c;
    font-size: 0.85rem;
    margin-top: 4px;
}

/* قسم زر الارسال بعد جميع مجموعات النموذج */
.form > .form-group ~ .form-actions {
    margin-top: 2rem;
    padding-top: 1.5rem;
    border-top: 1px solid #eee;
}

حالة الاستخدام 3: تنقل الشريط الجانبي

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

/* اقسام الشريط الجانبي ذات المستوى الاعلى */
.sidebar > .nav-section + .nav-section {
    margin-top: 2rem;
    padding-top: 2rem;
    border-top: 1px solid #eee;
}

/* عناوين الاقسام */
.nav-section > h3 {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #999;
    margin-bottom: 0.75rem;
}

/* روابط التنقل المباشرة */
.nav-section > ul > li > a {
    display: block;
    padding: 8px 12px;
    color: #333;
    border-radius: 6px;
    transition: all 0.2s ease;
}

.nav-section > ul > li > a:hover {
    background-color: #f0f0f0;
    color: #3498db;
}

/* روابط التنقل الفرعية المتداخلة مع مسافة بادئة واصغر حجما */
.nav-section > ul > li > ul > li > a {
    padding-left: 32px;
    font-size: 0.9rem;
    color: #666;
}

/* الحالة النشطة والاشقاء التالين */
.nav-section li.active > a {
    background-color: #ebf5fb;
    color: #3498db;
    font-weight: 600;
}

.nav-section li.active ~ li > a {
    opacity: 0.7;
}

جدول مقارنة محددات الدمج

اليك مرجع سريع يقارن بين محددات الدمج الاربعة جنبا الى جنب:

محددات الدمج الاربعة في لمحة

/* السلالة (مسافة) -- اي عمق */
.parent .target { }
/* يحدد: اي .target داخل .parent، بغض النظر عن العمق */

/* الفرع (>) -- العناصر الفرعية المباشرة فقط */
.parent > .target { }
/* يحدد: عناصر .target التي هي فرعية مباشرة لـ .parent */

/* الشقيق المجاور (+) -- التالي مباشرة */
.reference + .target { }
/* يحدد: .target مباشرة بعد .reference (نفس الاصل) */

/* الشقيق العام (~) -- جميع التالين */
.reference ~ .target { }
/* يحدد: جميع عناصر .target بعد .reference (نفس الاصل) */

الاخطاء الشائعة ونصائح التصحيح

الخطأ 1: الخلط بين محدد السلالة ومحدد الفرع

الخلط بين السلالة والفرع

/* المشكلة: تريد تنسيق عناصر المستوى الاعلى فقط، لكنك
   استخدمت محدد السلالة الذي ينسق ايضا العناصر المتداخلة */
.menu li {
    font-weight: bold;  /* هذا يؤثر على جميع li، بما في ذلك المتداخلة */
}

/* الحل: استخدم محدد الفرع */
.menu > li {
    font-weight: bold;  /* العناصر الفرعية المباشرة فقط */
}

/* البديل: اعادة تعيين العناصر المتداخلة */
.menu li {
    font-weight: bold;
}
.menu li li {
    font-weight: normal;  /* اعادة تعيين للمتداخلة */
}

الخطأ 2: توقع التحديد العكسي

محددات الاشقاء تعمل للأمام فقط

/* المشكلة: تريد تنسيق العنصر قبل العنصر النشط */
/* هذا لا يعمل -- CSS لا يمكنها تحديد الاشقاء السابقين */
.item + .active {
    /* هذا يحدد .active وليس .item! */
}

/* لا يوجد محدد "شقيق سابق" في CSS.
   محددات + و ~ تنظر فقط للأمام.

   خيارات الحل البديل:
   1. استخدم JavaScript لإضافة فئة للعنصر السابق
   2. اعد هيكلة HTML مع ترتيب flexbox او الاتجاه
   3. استخدم :has() (المتصفحات الحديثة) */

/* حل حديث مع :has() */
.item:has(+ .active) {
    /* هذا يحدد .item الذي يتبعه .active مباشرة */
    border-right: none;
}

الخطأ 3: نسيان ان الاشقاء يجب ان يشتركوا في نفس الاصل

متطلب نفس الاصل

/* HTML */
<div class="wrapper">
    <h2>العنوان</h2>
</div>
<p>هذه الفقرة ليست شقيقة لـ h2!</p>

/* هذا لن يعمل لأن p و h2 لهما اصل مختلف */
h2 + p {
    /* لا شيء محدد -- ليسا اشقاء */
}

/* لجعل هذا يعمل، يجب ان يشتركا في نفس الاصل:
<div class="wrapper">
    <h2>العنوان</h2>
    <p>الآن هذه شقيقة لـ h2</p>
</div>
*/

الخطأ 4: الخصوصية المفرطة مع محددات الدمج المتسلسلة

تجنب المحددات المحددة بشكل مفرط

/* سيء: محدد جدا -- صعب التجاوز وهش */
body > main > section.content > article > div.body > p + p {
    margin-top: 1rem;
}

/* جيد: محدد بما يكفي */
.article-body > p + p {
    margin-top: 1rem;
}

/* سيء: خلط الكثير من محددات الدمج يجعله غير مقروء */
.sidebar > nav ul li a ~ span + .icon > svg {
    fill: currentColor;
}

/* جيد: استخدم فئة وصفية بدلا من ذلك */
.nav-icon svg {
    fill: currentColor;
}
خطأ شائع: كتابة محددات اكثر تحديدا مما تحتاج. كل مستوى اضافي من محددات الدمج يزيد الخصوصية ويجعل CSS اصعب في التجاوز لاحقا. اتبع قاعدة اقل خصوصية: استخدم ابسط محدد يستهدف العناصر التي تحتاجها بشكل صحيح. إذا كان محدد الفئة يعمل، فضله على سلسلة محددات دمج معقدة.

تصحيح مشاكل محددات الدمج

عندما لا تعمل محددات الدمج كما هو متوقع، اليك خطوات التصحيح:

  1. افحص بنية DOM: افتح ادوات المطور في متصفحك وتحقق من العلاقات الفعلية بين الاصل والفرع والاشقاء. قد لا تكون العناصر منظمة بالطريقة التي تتوقعها.
  2. تحقق من عقد النص: في DOM، المسافات البيضاء بين العناصر تنشئ عقد نص. بينما لا تؤثر هذه على محددات الاشقاء في CSS (CSS تتجاهل عقد النص لـ + و ~)، يمكنها ان تربك نموذجك الذهني.
  3. تحقق من اتجاه المحدد: تذكر ان العنصر المنسق هو دائما العنصر على الجانب الايمن من محدد الدمج. إذا كتبت A + B، فإن B هو الذي يتم تنسيقه وليس A.
  4. تحقق من انواع العناصر: إذا كتبت h2 + p لكن هناك <div> بين <h2> و <p>، فلن يطابق محدد الشقيق المجاور. استخدم h2 ~ p إذا كان من الممكن وجود عناصر اخرى بينهما.
  5. اختبر بالتمييز: اضف outline: 3px solid red !important; مؤقتا لمحددك لترى بصريا اي العناصر يتم مطابقتها.

تمرين 1: نظام قائمة التنقل

ابن قائمة تنقل افقية من مستويين بالمتطلبات التالية:

  • انشئ <nav> يحتوي على <ul> مع 5 عناصر <li>، كل منها يحتوي على رابط <a>.
  • اثنان من العناصر يجب ان يحتويا على قوائم فرعية متداخلة <ul> منسدلة مع 3 عناصر لكل منها.
  • استخدم محدد الفرع لجعل عناصر <li> ذات المستوى الاعلى فقط تُعرض بشكل مضمن.
  • استخدم محدد السلالة لتنسيق جميع عناصر <a> داخل nav.
  • استخدم محدد الفرع لإعطاء انماط مختلفة لروابط المستوى الاعلى مقابل روابط القائمة المنسدلة.
  • استخدم محدد الشقيق المجاور لإضافة فاصل حد يسار بين عناصر المستوى الاعلى.
  • استخدم محدد الشقيق العام لتخفيت العناصر بعد العنصر النشط في القائمة المنسدلة.

تمرين 2: تخطيط منشور المدونة

انشئ صفحة منشور مدونة واستخدم محددات الدمج لتنسيق الطباعة:

  • انشئ <article> يحتوي على عنوان <h1>، وعدة اقسام <h2>، وفقرات، وصور، واقتباسات، وكتل شفرة.
  • استخدم > * + * (فرع + شقيق مجاور) على المقال لإضافة ايقاع عمودي للمسافات.
  • استخدم > h1 + p لتنسيق الفقرة الرئيسية بشكل مختلف (خط اكبر، لون افتح).
  • استخدم > * + h2 لإضافة هامش علوي اضافي قبل كل عنوان قسم.
  • استخدم h2 + h3 لتقليل المسافة عندما يتبع عنوان فرعي عنوانا.
  • استخدم blockquote ~ p لإضافة حد يسار خفيف للفقرات التي تتبع الاقتباسات.
  • استخدم محدد السلالة لتنسيق الروابط داخل الفقرات بشكل مختلف عن روابط التنقل.

تمرين 3: جدول الاسعار

ابن جدول مقارنة اسعار باستخدام محددات الدمج:

  • انشئ 3 بطاقات اسعار جنبا الى جنب في حاوية.
  • استخدم > لضمان ان البطاقات الفرعية المباشرة فقط تحصل على تنسيق الشبكة/المرن.
  • استخدم .card + .card لإضافة حد يسار بين البطاقات المتجاورة.
  • استخدم .featured ~ .card لجعل جميع البطاقات بعد المميزة اصغر قليلا.
  • داخل كل بطاقة، استخدم > * + * لمسافات عمودية متسقة.
  • استخدم .price + .features للتحكم في المسافة بين السعر وقائمة الميزات.
  • استخدم .features > li + li لإضافة فواصل بين عناصر الميزات.

الملخص

في هذا الدرس تعلمت عن محددات الدمج الاربعة في CSS وكيف تحدد العلاقات بين العناصر:

  • محدد السلالة (مسافة) يحدد العناصر المتداخلة على اي عمق. هو محدد الدمج الاكثر استخداما لكنه قد يكون اقل كفاءة للتحديدات العميقة جدا او الواسعة.
  • محدد الفرع (>) يحدد فقط العناصر الفرعية المباشرة. هو اساسي للتنسيق القائم على المكونات حيث تحتاج تحكما دقيقا في اي مستوى تداخل يتم تنسيقه.
  • محدد الشقيق المجاور (+) يحدد الشقيق التالي مباشرة. مثالي للتنسيق السياقي مثل "الفقرة بعد العنوان" او نمط المسافات "بومة المفصولة الدماغ".
  • محدد الشقيق العام (~) يحدد جميع الاشقاء التالين. يدعم الانماط التفاعلية بـ CSS فقط مثل خدعة مربع الاختيار للاكورديونات والمفاتيح.
  • يمكن ربط محددات الدمج معا للتحديدات المعقدة والدقيقة، لكن يجب تجنب الخصوصية المفرطة.
  • تقيم المتصفحات المحددات من اليمين الى اليسار، لذا يمكن ان يكون لمحددات السلالة العميقة تأثيرات على الاداء في الصفحات الكبيرة.
  • محددات الاشقاء تعمل فقط للأمام في DOM -- لا توجد طريقة CSS اصلية لتحديد شقيق سابق (رغم ان :has() تقدم حلا حديثا).
  • عند التصحيح، تحقق دائما من بنية DOM الفعلية وتذكر ان العنصر المنسق هو دائما العنصر على الجانب الايمن من محدد الدمج.

ES
Edrees Salih
منذ 11 ساعة

We are still cooking the magic in the way!