EduFlow
إتقان CSS الحديثة
⁦0%⁩

الوحدة 1 · الـ Cascade كما هو فعلًا

طبقات الـ Cascade باستخدام @layer

18 دقراءة 4 دبيئة تجريب الكود

الدرس في لمحة

نظّم ملف الأنماط في طبقات cascade بحيث تفوز مجموعات الأنماط كاملة (إعادة الضبط والـ components والـ utilities) بحسب ترتيب الـ layers لا بحسب الـ specificity.

  1. 1أعلن الترتيب ثم املأ الـ layers
  2. 2الأنماط خارج الـ layers تفوز
  3. 3التصريحات المهمّة تقلب الترتيب
  4. 4الـ layers المتداخلة والتراجع
  5. 5تبنّي الـ layers في قاعدة كود قائمة
  6. 6دورك الآن

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

نما في ملف أنماط Waypoint أربعة أنواع من CSS: إعادة ضبط (reset)، وأنماط أساسية للعناصر، وcomponents مثل بطاقة الجلسة، وأدوات utilities ذات المهمّة الواحدة مثل .bg-accent يرشّها فريق المحتوى في الـ HTML. يُفترض أن تفوز الـ utilities؛ فهذا هو الغرض منها أصلًا. لكن selector component مثل .schedule .session-card .badge درجته (0,3,0)، والـ utility درجتها (0,1,0)، فتخسر الـ utility ويكتب أحدهم !important من جديد.

لم تُصمَّم الـ specificity قطّ للتعبير عن أن «هذه المجموعة من الأنماط أعلى رتبة من تلك». أما طبقات الـ cascade (cascade layers) فصُمِّمت لهذا بالضبط.

أعلن الترتيب ثم املأ الـ layers

الـ layer (طبقة) وعاء مسمّى من القواعد. تعلن الترتيب مرة واحدة، في أعلى ملف الـ CSS:

styles.css
@layer reset, base, components, utilities;

ثم تضع القواعد في الـ layers، بأيّ ترتيب ومن أيّ ملف:

CSS
@layer components {
  .schedule .session-card .badge {
    background: #ede9fe;
    color: #5b21b6;
  }
}

@layer utilities {
  .bg-accent { background: #fde68a; }
}

الآن تفوز .bg-accent على خلفية الـ component رغم أن الـ specificity الخاصة بها أقل. حين يصل الـ cascade إلى الخطوة 3 (الـ layers) يرى أن التصريحين من layerين مختلفتين، فيختار المُعلنة لاحقًا، ولا يصل إلى الـ specificity أبدًا. أما داخل الـ layer الواحدة فتعمل الـ specificity وترتيب الظهور كما تعرفهما.

طبقات مرصوصة من الأقل أولوية إلى الأعلى: reset ثم base ثم components ثم utilities، وفي القمة الأنماط خارج الـ layers. سهم على اليمين يشير إلى الأعلى بعنوان أولوية أعلى. @layer reset @layer base @layer components @layer utilities أنماط خارج الـ layers أولوية أعلى
الـ layers اللاحقة تفوز في التصريحات العادية، والأنماط خارج الـ layers تجلس في القمة

أول تعليمة @layer هي التي تثبّت الترتيب. إن كتبت @layer utilities { … } قبل أن تعلن components أصلًا، تصبح utilities هي الـ layer الأولى (الأدنى). لهذا مكان تعليمة الترتيب في أعلى ملف الأنماط الرئيسي تمامًا.

الأنماط خارج الـ layers تفوز

أيّ قاعدة عادية ليست داخل layer تذهب إلى layer ضمنية تتغلّب على كل الـ layers المسمّاة. يبدو هذا معكوسًا في البداية، لكنه ما يجعل تبنّي الـ layers ممكنًا: تستطيع تغليف الكود الجديد في layers اليوم، وتحتفظ الـ CSS الحالية غير المنتمية إلى layer بسلوكها كما هو.

والوجه الآخر لهذا فخّ كلاسيكي.

ويمكن وضع ملفات الأطراف الثالثة في layer مباشرةً عند استيرادها:

CSS
@layer vendor, reset, base, components, utilities;
@import url("calendar-widget.css") layer(vendor);

لاحظ أن قواعد @import يجب أن تأتي قبل أيّ قواعد أخرى باستثناء @charset وتعليمات @layer، ولهذا بالضبط تستطيع تعليمة الترتيب أن تجلس فوقها.

التصريحات المهمّة تقلب الترتيب

في تصريحات !important تنعكس أولوية الـ layers: القاعدة المهمّة في reset تتغلّب على القاعدة المهمّة في utilities، والقواعد المهمّة داخل الـ layers تتغلّب على المهمّة خارجها. وهذا يحاكي طريقة عمل المصادر (قاعدة المستخدم المهمّة تتغلّب على قاعدتك)، ويعطي الـ layers المنخفضة طريقة لحماية ما هو جوهري. تستطيع إعادة الضبط أن تثبّت [hidden] { display: none !important; } فلا يستطيع أيّ component أن يُظهر محتوى مخفيًا بالخطأ.

الـ layers المتداخلة والتراجع

يمكن أن تتداخل الـ layers: @layer components.cards { … } تنشئ layer اسمها cards داخل components، وتُحسم أولويتها داخل الـ layer الأم. تستخدم الفرق هذا لإعطاء كل مجلد components طبقة فرعية خاصة به دون أن يتأثّر الترتيب العام.

وهناك كلمة مفتاحية أخرى تعمل مع الـ layers: revert-layer. ضبط color: revert-layer يعيد الخاصية إلى ما كانت ستنتجه الـ layers السابقة، كأن تصريح هذه الـ layer غير موجود. وهي مفيدة في utility مثل .reset-color { color: revert-layer; }.

تبنّي الـ layers في قاعدة كود قائمة

لا تحتاج إلى إعادة كتابة. في قاعدة كود Waypoint استغرق الانتقال ظهيرة واحدة وثلاث خطوات:

  1. أضف تعليمة الترتيب في أعلى ملف الأنماط الرئيسي تمامًا، وضع layer اسمها legacy أولًا.
  2. غلّف كل ملف موجود بـ @layer legacy { … }، أو استورده بـ layer(legacy). لن يتغيّر شيء بصريًا، لأن القواعد القديمة ما زالت تتنافس فيما بينها تمامًا كما كانت.
  3. كلما لمست component، انقل قواعده من legacy إلى components. كل نقلة كهذه لا يمكن إلا أن تجعل كودك الجديد أقوى مقارنةً بالقديم، لا أضعف أبدًا.

العائد يصل سريعًا: تتوقّف الـ components الجديدة عن الحاجة إلى selectors ثقيلة لتهزم القديمة، وتستطيع حذف تصريحات !important واحدًا تلو الآخر كلما زال سببه.

دورك الآن

في التمرين، لشارة Waypoint selector component ثقيل وutility يجب أن تتجاوزه. ضع القواعد في layers لتفوز الـ utility دون تعديل أيّ selector ودون إضافة !important. الـ layers تحسم «أيّ مجموعة تفوز»؛ والدرس التالي يتناول «أيّ قيمة»، باستخدام الـ custom properties كمقابض تكشفها الـ components لديك.

أهم النقاط

  • أعلن ترتيب الـ layers مرة واحدة في الأعلى بـ @layer reset, base, components, utilities;، والـ layers اللاحقة تفوز على السابقة بغضّ النظر عن الـ specificity.
  • الـ specificity ما زالت مهمة، لكن فقط بين التصريحات الموجودة داخل الـ layer نفسها.
  • الأنماط العادية التي لا تنتمي إلى أيّ layer تتغلّب على كل نمط داخل layer، لذا غلّف الـ CSS القديمة أو الخارجية في layer بدل أن تتركها طليقة.
  • !important تعكس ترتيب الـ layers: التصريح المهمّ في layer مبكرة يتغلّب على التصريح المهمّ في layer لاحقة.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

ما الخلفية التي يأخذها .badge.sold-out؟

CSS
@layer components, utilities;
@layer utilities { .sold-out { background: gold; } }
@layer components { .schedule .card .badge { background: lavender; } }
السؤال 2 من 4

أضفت @layer reset, components; وغلّفت الكود، لكن قاعدة قديمة h2 { color: black; } تقع خارج أيّ layer ما زالت تتجاوز عناوين الـ components لديك. لماذا؟

السؤال 3 من 4

كيف تضع ملف أنماط من طرف ثالث في الـ layer الأقل أولوية؟

السؤال 4 من 4

في layer اسمها components يقول تصريح color: red !important، وفي layer لاحقة اسمها utilities يقول تصريح آخر color: blue !important. أيّهما يفوز؟

تدريب

بيئة تجريب الكود

دع الـ utility تفوز بالـ layers

يجب أن تكون شارة Sold out صفراء (#fde68a) لأنها تحمل الـ utility .bg-accent، لكن selector الـ component .schedule .session-card .badge يتفوّق عليها في الدرجة. ضع القواعد في طبقات cascade (reset وcomponents وutilities بهذا الترتيب) لتفوز الـ utilities. أبقِ كل selector كما هو تمامًا ولا تستخدم !important. ويجب أن تحتفظ شارة Layout العادية بنمط الـ component الخزامي (lavender).

<section class="schedule">
  <article class="session-card">
    <h2>Container Queries in Production</h2>
    <span class="badge">Layout</span>
    <span class="badge bg-accent">Sold out</span>
  </article>
</section>جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

المعاينة

الـ console

(لا مخرجات)

الفحوص

  • شارة Sold out صفراء
  • شارة Layout تحتفظ بنمط الـ component الخزامي
  • الـ CSS تستخدم كتل @layer
  • selector الـ component لم يتغيّر
  • لا توجد !important في أيّ مكان من الـ CSS