حوّل عنصر BEM إلى مكوّن عندما يكون له غرض واضح ويمكنه امتلاك تنفيذه خارج الكتلة الأم. استخدم التمرين المحلي أدناه على Mac لاختبار هذا الحد قبل إعادة تسمية الأصناف أو نقل CSS.

ما الذي يجعل العنصر مستقلًا؟

بالنسبة إلى من يصون صفحة HTML مكتوبة يدويًا، يتمثل السؤال العملي في ما إذا كان ينبغي أن يظل القسم الآخذ في التوسع جزءًا من العنصر الأب أم أن يصبح كتلة تُصان بشكل منفصل. تعرّف BEM الكتلة بأنها مكوّن مستقل منطقيًا ووظيفيًا؛ وينتمي العنصر إلى كتلة ولا يمكن استخدامه مستقلًا عنها. ويمكن أن تحتوي الكتل على كتل أخرى. المفاهيم الأساسية

لنفترض وجود صفحة اصطناعية تحتوي على كتلة workbench. يضم workbench__preview شكلًا تجريديًا ووسمًا وتعليقًا توضيحيًا. في البداية، تخدم العناصر الثلاثة طاولة العمل وحدها. لاحقًا، تصبح هناك حاجة إلى المعاينة نفسها في منطقة shelf ضيقة. يمنحك هذا الموضع الثاني مهمة استخراج ملموسة: حدّد ما إذا كان بالإمكان تحويل المعاينة إلى كتلة shape-tile لها مظهرها وبنيتها الداخلية الخاصة.

لا يحدد العمق وحده ذلك. تسمح BEM بعناصر متداخلة في DOM مع إبقاء أسمائها مسطحة: workbench__preview وworkbench__label وworkbench__caption. والاسم مثل workbench__preview__caption يعبّر خطأً عن عنصر ينتمي إلى عنصر آخر. كما يقرّ دليل البدء السريع الرسمي بإمكانية استخدام كتلة خدمية عندما يحتاج العنصر المعقد إلى أجزاء داخلية منظّمة بشكل مستقل. البدء السريع

من المفيد التمييز بين نقل الترميز إلى قالب منفصل لتحسين سهولة قراءته، وإنشاء كتلة BEM جديدة. يمكنك إجراء التغيير الأول من دون الالتزام فورًا بالثاني. اجعل حدود الكتلة واضحة عندما تتمكن من وصف ما يملكه الجزء المستخرج، وما يوفّره السياق الحاوي، وكيف سيُستخدم في موضع آخر.

اختبر التبعيات قبل الاستخراج

أداة اتخاذ القرار التالية منهج تحريري مستمد من مبدأ الاستقلال في BEM، وليست نظام تقييم رسميًا. طبّقها على شجرة فرعية مرشحة واحدة بدلًا من تقييم الصفحة كلها دفعة واحدة.

السؤال ما يدعم الاستخراج سبب للإبقاء على العنصر
هل له غرض واضح؟ «يعرض شكلًا مع وسم وتعليق توضيحي» غرضه الوحيد هو «الغلاف الداخلي لطاولة العمل»
هل يمكنه تولّي تنسيقه الداخلي؟ تنتقل حدوده وتباعده وخطه معًا لا تنفصل هذه القواعد عن بنية العنصر الأب
هل يمكن للسياق الحاوي توفير الموضع بشكل منفصل؟ يتحكم السياق الحاوي بالمساحة المتاحة والفجوات المحيطة يحتاج العنصر المرشح إلى تخطيط سلف محدد
هل تصف اختلافاته العنصر نفسه؟ يكون للبلاطة المدمجة معنى في مواضع متعددة تُسمّى كل الاختلافات باسم عنصر أب معيّن
هل سيفيد الصون المنفصل الآن؟ يوجد موضع ثانٍ أو مسؤولية داخلية كبيرة سيضيف الاستخراج واجهة لا استخدام حاليًا لها

اكتب جملة واحدة قبل تغيير الشيفرة: «تتولى shape-tile شكلها ووسمها وتعليقها التوضيحي وتباعدها الداخلي؛ ويتولى السياق الحاوي الموضع والعرض المتاح». إذا استمرت الجملة في التوسع لتشمل ترتيب أعمدة طاولة العمل أو ترتيب العناصر الشقيقة، فأعد النظر في مكان وضع الحد.

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

على سبيل المثال، يمكن أن تعبّر class="shape-tile workbench__preview" عن الهويتين معًا. دع shape-tile يعرّف حدودها وتخطيطها الداخلي، ودع workbench__preview يعرّف موضعها. تجنّب تعيين الخاصية نفسها عبر الهويتين إلا إذا كان التجاوز جزءًا مقصودًا من العقد.

أنشئ مقارنة محلية على Mac

أنشئ مجلدًا جديدًا لهذا التمرين كي تتمكن من مقارنة التصميم المستخرج من دون تعديل صفحة موجودة. ستحتاج إلى محرر نصوص عادي ومتصفح لسطح المكتب؛ ولا يتطلب المثال تثبيت حزم أو استخدام JavaScript أو تنزيل خطوط أو ملفات صور.

في TextEdit، اختر File > New، ثم Format > Make Plain Text. الصق HTML أدناه واحفظه باسم index.html، واختر Use .html إذا طُلب منك ذلك. توثّق Apple هذه الخطوات، وتشرح أيضًا كيفية إعادة فتح HTML بوصفه مصدرًا باستخدام Ignore rich text commands. العمل مع مستندات HTML في TextEdit على Mac

أنشئ مستند HTML كاملًا

يضع هذا المستند المكوّن المقترح نفسه في سياقين حاوِيَين. كل التسميات اصطناعية، والشكل التجريدي مرسوم باستخدام CSS. احفظ ما يلي باسم index.html.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Shape tile boundary exercise</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body class="demo">
  <h1>Shape tile boundary exercise</h1>
  <main class="demo__regions">
    <section class="workbench">
      <h2>Workbench A</h2>
      <div class="shape-tile workbench__preview">
        <span class="shape-tile__shape" aria-hidden="true"></span>
        <div class="shape-tile__content">
          <h3 class="shape-tile__label">Form A</h3>
          <p class="shape-tile__caption">Rounded sample, first arrangement.</p>
        </div>
      </div>
    </section>
    <section class="shelf">
      <h2>Shelf B</h2>
      <div class="shape-tile shelf__preview">
        <span class="shape-tile__shape" aria-hidden="true"></span>
        <div class="shape-tile__content">
          <h3 class="shape-tile__label">Form B</h3>
          <p class="shape-tile__caption">Rounded sample, second arrangement.</p>
        </div>
      </div>
    </section>
  </main>
</body>
</html>

أضف ورقة الأنماط كاملة

أنشئ ملفًا آخر بنص عادي باسم styles.css في المجلد نفسه. تأكد من أن اسمه الفعلي هو styles.css وليس styles.css.txt. الصق ورقة الأنماط كاملة:

/* Page and host styles */
.demo {
  margin: 0 auto;
  padding: 24px;
  max-width: 960px;
  font-family: system-ui, sans-serif;
  background: #f1f3f5;
  color: #243047;
}
.demo__regions {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
}
.workbench,
.shelf {
  box-sizing: border-box;
  padding: 16px;
  max-width: 100%;
  border: 1px dashed #6b778a;
}
.workbench { width: 480px; }
.shelf { width: 256px; }
.workbench__preview { margin-top: 24px; }
.shelf__preview { margin-top: 12px; }

/* Independent component styles */
.shape-tile {
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 16px;
  border: 1px solid #718096;
  border-radius: 12px;
  background: #fff;
  color: #243047;
  font: 16px/1.5 system-ui, sans-serif;
}
.shape-tile__shape {
  flex: 0 0 48px;
  height: 48px;
  border-radius: 16px 24px 12px 24px;
  background: #536dbe;
}
.shape-tile__content {
  flex: 1 1 160px;
  min-width: 0;
  overflow-wrap: anywhere;
}
.shape-tile__label {
  margin: 0;
  font-size: 18px;
  line-height: 1.3;
}
.shape-tile__caption { margin: 6px 0 0; }

افتح index.html في Safari أو متصفح آخر لسطح المكتب. المقارنة المقصودة هي طاولة عمل أوسع ورف أضيق. تشترك البلاطات فيهما في تنسيق المكوّن؛ وتحدد المساحة المتاحة ما إذا كان الشكل والنص سيتسعان جنبًا إلى جنب أم سيلتفّان.

عقد المورد مهم هنا: ينشئ rel="stylesheet" مورد ورقة أنماط خارجية، ويحدد href="styles.css" الملف الذي يحتاج إليه هذا المستند. إضافة صنف BEM لا تنشئ رابط المورد هذا. أبقِ الملفين معًا عند نقل التمرين. يعرّف معيار HTML علاقة ورقة الأنماط هذه. معيار HTML: نوع الرابط «stylesheet»

كيف تعرف أن الاستخراج نجح؟

استخدم المقارنة كتمرين تشخيصي. تستند النتائج المتوقعة أدناه إلى الشيفرة المقدّمة؛ وهي فحوص تجريها بنفسك في المتصفح، وليست نتائج اختبارات متصفح مُبلّغًا عنها.

  1. تحقق من الحالة الأساسية. ينبغي أن تكون خلفية كلتا البلاطتين بيضاء، وأن تحتوي كل منهما على شكل أزرق مستدير ووسم وتعليق توضيحي. إذا بدا كل شيء بلا تنسيق، فتحقق من اسم ملف ورقة الأنماط والرابط قبل تقييم حدود المكوّن.
  2. أزل صنف موضع واحدًا. احذف workbench__preview من البلاطة الأولى، ثم احفظ وأعد التحميل. ينبغي أن يتغير الهامش العلوي مع بقاء مظهرها الداخلي سليمًا.
  3. أزل صنفًا من السياق الحاوي. أزل مؤقتًا workbench من القسم الحاوي. ينبغي أن يختفي إطار السياق الحاوي وعرضه الثابت؛ مع احتفاظ البلاطة بأنماط المكوّن.
  4. غيّر المكوّن المشترك. غيّر نصف قطر الحدود في .shape-tile. ينبغي أن يتغير كلا المثالين من دون تعديل محدد أيٍّ من السياقين الحاويين.
  5. اختبر المحتوى. استبدل أحد التعليقات التوضيحية بجملة اصطناعية أطول، وضيّق نافذة المتصفح. تحقق من التفاف النص ومن بقاء النص كله ظاهرًا.

فسّر الإخفاقات بحسب المسؤولية. اختفاء حد بعد إزالة صنف السياق الحاوي يعني أن نمطًا للمكوّن قد يظل تابعًا لمحدد السياق الحاوي. يشير التباعد المحيط غير المتوقع إلى قواعد التموضع. وقد تكشف اختلافات النص عن أنماط موروثة أو محددات عامة. أصلح التبعية المسؤولة قبل إضافة تجاوز آخر.

لا تنشئ تسمية BEM عزلًا للأنماط تفرضه المتصفحات. يستمر توريث CSS عبر شجرة المستند: فالخصائص الموروثة تأخذ قيمها من العنصر الأب عندما لا توفّر سلسلة التتالي قيمة للعنصر. يحدّد ذلك مواصفات CSS للتتالي والتوريث، وتوضحه MDN. وحدة CSS للتتالي والتوريث، المستوى 5، القسم 7.2، التوريث

يضبط المثال عمدًا الخط ولون النص للبلاطة على العنصر الجذر. وقد يكون توريث خطوط الموقع مرغوبًا بدلًا من ذلك في صفحة حقيقية. سجّل ذلك باعتباره تبعية. يعني الاستقلال أن البيئة المطلوبة مفهومة وقابلة للنقل؛ ولا يعني بالضرورة إعادة إنتاج كل إعداد افتراضي للمتصفح داخل كل مكوّن.

متى ينبغي الإبقاء على العنصر؟

أبقِ العنصر المرشح عنصرًا عندما يظل معناه وتنفيذه خاصين بالعنصر الأب. يمكن أن يحتوي غلاف محاذاة خاص بطاولة العمل على عدة عناصر فرعية من دون أن يحتاج إلى هوية عامة منفصلة. اجعل أسماء BEM مسطحة وحسّن تنظيمها قبل إدخال كتلة جديدة.

وعلى العكس، قد يستحق المكوّن المستخدم مرة واحدة فقط الاستخراج عندما تكون مسؤوليته الداخلية كبيرة وحدود تبعياته واضحة. اعتبر إعادة الاستخدام دليلًا داعمًا، لا عددًا مطلوبًا. في هذا التمرين، يجعل الموضع الثاني الحدود أسهل في الفحص؛ لكنه لا يثبت وجود قاعدة عامة تلزم باستخدام العنصر مرتين.

أعِد النظر أيضًا في أي استخراج تتراكم فيه الاختلافات الخاصة بالسياق الحاوي. توحي أسماء مثل shape-tile--inside-workbench بأن التموضع أصبح جزءًا من واجهة المكوّن. اسأل أولًا ما إذا كان الاختلاف ينتمي إلى workbench__preview. خصّص اختلافات المكوّن لحالات يمكنك شرحها بمصطلحات المكوّن نفسه.

هل يغيّر تحديد النطاق في CSS الحديث هذا القرار؟

تستطيع قاعدة @scope تقييد المواضع التي تطابقها المحددات المحاطة بها، ما قد يساعد في إدارة المحددات ضمن نطاق فرعي من المستند. تصنّف MDN القاعدة حاليًا ضمن Baseline 2026، ومتاحة عبر إصدارات المتصفحات الحالية منذ مارس 2026، مع الإشارة إلى احتمال افتقار الأجهزة أو المتصفحات الأقدم إلى الدعم. لا تفترض أن كل تثبيت لـ Mac يدعمها. قاعدة CSS ‏@scope

يستخدم التمرين المقدّم محددات أصناف عادية ولا يتطلب @scope. أبقِ الأنماط الأساسية للمكوّن في تلك القواعد عند دعم متصفحات لا تدعم تحديد النطاق. قد يحسّن تحديد النطاق طريقة التعبير عن الحدود، لكن قرار الملكية يظل بحاجة إلى شرح واضح لغرض المكوّن وتبعياته وموضعه.

استخرج العنصر المعقد عندما تتمكن من نقل غرضه وتنفيذه الداخلي معًا، وإبقاء التخطيط المحيط مع السياق الحاوي، وإظهار النتيجة في سياق آخر. إذا ظلت تلك المسؤوليات متشابكة، فأبقِ العنصر بينما توضّحها؛ فتقصير اسم الصنف وحده لن يُتم إعادة الهيكلة.

المصادر