ترويض التتالي باستخدام BEM ومحددات CSS الحديثة وذكاء بيانات PlatoBlockchain. البحث العمودي. منظمة العفو الدولية.

ترويض Cascade باستخدام BEM ومحددات CSS الحديثة

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

أنا شخصياً أعتقد أن BEM جيد ، وأعتقد أنه يجب عليك استخدامه. لكنني أفهم أيضًا لماذا قد لا تفعل ذلك.

بغض النظر عن رأيك في BEM ، فإنه يقدم العديد من الفوائد ، وأكبرها أنه يساعد على تجنب تضارب الخصوصية في CSS Cascade. هذا لأنه ، إذا تم استخدامه بشكل صحيح ، فإن أي محددات مكتوبة بتنسيق BEM يجب أن يكون لها نفس درجة الخصوصية (0,1,0). لقد صممت CSS للعديد من مواقع الويب واسعة النطاق على مر السنين (فكر في الحكومة والجامعات والبنوك) ، وهي في هذه المشاريع الكبيرة حيث وجدت أن BEM يتألق حقًا. تعد كتابة CSS أكثر متعة عندما تكون واثقًا من أن الأنماط التي تكتبها أو تعدلها لا تؤثر على جزء آخر من الموقع.

هناك بالفعل استثناءات حيث يعتبر إضافة الخصوصية أمرًا مقبولًا تمامًا. على سبيل المثال: :hover و :focus فصول زائفة. هؤلاء لديهم درجة خصوصية تبلغ 0,2,0. آخر هو العناصر الزائفة - مثل ::before و ::after - التي لها درجة خصوصية تبلغ 0,1,1. بالنسبة لبقية هذه المقالة ، دعنا نفترض أننا لا نريد أي زحف آخر للخصوصية. 🤓

لكنني لست هنا حقًا لأبيعك على BEM. بدلاً من ذلك ، أريد أن أتحدث عن كيفية استخدامه جنبًا إلى جنب مع محددات CSS الحديثة - فكر :is(), :has(), :where()، وما إلى ذلك - لكسب حتى الأكثر من ذلك السيطرة على الشلال.

ما هذا عن محددات CSS الحديثة؟

محددات CSS المستوى 4 المواصفات يعطينا بعض الطرق الجديدة القوية لتحديد العناصر. بعض من مفضلاتي تشمل :is(), :where()و :not()، كل منها مدعوم من قبل جميع المتصفحات الحديثة وهو آمن للاستخدام في أي مشروع تقريبًا في الوقت الحاضر.

:is() و :where() هي في الأساس نفس الشيء باستثناء كيفية تأثيرها على الخصوصية. خاصة، :where() دائما لديه درجة خصوصية 0,0,0. نعم ، حتى :where(button#widget.some-class) ليس له خصوصية. وفي الوقت نفسه ، خصوصية :is() هو العنصر الموجود في قائمة الحجج بأعلى دقة. لذلك ، لدينا بالفعل تمييز متسلسل بين محددين حديثين يمكننا العمل بهما.

الأقوياء بشكل لا يصدق :has() الطبقة الزائفة العلائقية هي أيضًا الحصول بسرعة على دعم المتصفح (وهي أكبر ميزة جديدة في CSS منذ ذلك الحين شبكة، برأيي المتواضع). ومع ذلك ، في وقت كتابة هذا التقرير ، دعم المتصفح لـ :has() ليست جيدة بما يكفي لاستخدامها في الإنتاج حتى الآن.

تمسك Lemme بأحد تلك الفئات الزائفة في BEM و ...

/* ❌ specificity score: 0,2,0 */
.something:not(.something--special) {
  /* styles for all somethings, except for the special somethings */
}

عذرًا! ترى أن درجة الخصوصية؟ تذكر ، مع BEM ، نريد بشكل مثالي أن يكون لدى المحددات لدينا درجة خصوصية تبلغ 0,1,0. لماذا 0,2,0 سيئ؟ ضع في اعتبارك هذا المثال نفسه الموسع:

.something:not(.something--special) {
  color: red;
}
.something--special {
  color: blue;
}

على الرغم من أن المحدِّد الثاني يكون أخيرًا في ترتيب المصدر ، فإن الخصوصية الأعلى للمحدد الأول (0,2,0) يفوز ولون .something--special سيتم تعيين العناصر على red. وهذا يعني ، على افتراض أن BEM الخاص بك مكتوب بشكل صحيح وأن العنصر المحدد له كلا من .something الفئة الأساسية و .something--special تم تطبيق فئة التعديل عليها في HTML.

عند استخدامها بلا مبالاة ، يمكن أن تؤثر هذه الفئات الزائفة على Cascade بطرق غير متوقعة. وهذه الأنواع من التناقضات هي التي يمكن أن تسبب الصداع ، خاصة على قواعد أكواد أكبر وأكثر تعقيدًا.

دانغ. إذن ماذا الآن؟

تذكر ما كنت أقوله :where() وحقيقة أن خصوصيتها صفر؟ يمكننا استخدام ذلك لصالحنا:

/* ✅ specificity score: 0,1,0 */
.something:where(:not(.something--special)) {
  /* etc. */
}

الجزء الأول من هذا المحدد (.something) يحصل على درجة الخصوصية المعتادة 0,1,0. لكن :where() - وكل شيء بداخله - له خصوصية 0، والتي لا تزيد من خصوصية المحدد أكثر من ذلك.

:where() يتيح لنا التعشيش

الأشخاص الذين لا يهتمون كثيرًا بالخصوصية (ومن المحتمل أن يكون هذا كثير من الناس ، لكي نكون منصفين) يتمتعون بشكل جيد عندما يتعلق الأمر بالتداخل. مع بعض ضربات لوحة المفاتيح الخالية من الهموم ، قد ينتهي بنا الأمر باستخدام CSS مثل هذا (لاحظ أنني أستخدم Sass للإيجاز):

.card { ... }

.card--featured {
  /* etc. */  
  .card__title { ... }
  .card__title { ... }
}

.card__title { ... }
.card__img { ... }

في هذا المثال ، لدينا ملف .card مكون. عندما تكون بطاقة "مميزة" (باستخدام امتداد .card--featured class) ، يجب تصميم عنوان البطاقة وصورتها بشكل مختلف. لكن ، مثلنا الآن تعرف ، ينتج عن الكود أعلاه درجة خصوصية لا تتوافق مع بقية نظامنا.

ربما قام الطالب الذي يذاكر كثيرا بالخصوصية الشديدة بفعل هذا بدلاً من ذلك:

.card { ... }
.card--featured { ... }
.card__title { ... }
.card__title--featured { ... }
.card__img { ... }
.card__img--featured { ... }

هذا ليس سيئا جدا ، أليس كذلك؟ بصراحة ، هذا CSS جميل.

هناك جانب سلبي في HTML بالرغم من ذلك. من المحتمل أن يكون مؤلفو BEM المحنكون على دراية بمنطق القوالب غير المرغوب فيه المطلوب لتطبيق فئات معدِّل مشروط على عناصر متعددة. في هذا المثال ، يحتاج قالب HTML إلى إضافة الامتداد --featured فئة معدل إلى ثلاثة عناصر (.card, .card__titleو .card__img) على الرغم من أنه ربما يكون أكثر في مثال واقعي. هذا كثير من if صياغات.

:where() يمكن أن يساعدنا المحدد في كتابة منطق قالب أقل - وعدد أقل من فئات BEM للتمهيد - دون إضافة إلى مستوى الخصوصية.

.card { ... }
.card--featured { ... }

.card__title { ... }
:where(.card--featured) .card__title { ... }

.card__img { ... }
:where(.card--featured) .card__img { ... }

هذا هو الشيء نفسه ولكن في Sass (لاحظ اللاحقة علامة العطف):

.card { ... }
.card--featured { ... }
.card__title { 
  /* etc. */ 
  :where(.card--featured) & { ... }
}
.card__img { 
  /* etc. */ 
  :where(.card--featured) & { ... }
}

ما إذا كان يجب عليك اختيار هذا النهج أم لا على تطبيق فئات معدلة على العناصر الفرعية المختلفة هي مسألة تفضيل شخصي. ولكن على الأقل :where() يعطينا الخيار الآن!

ماذا عن HTML غير BEM؟

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

مرة أخرى، :where() لديه ظهرنا. هذا الحل صعب بعض الشيء ، حيث نحتاج إلى الإشارة إلى فئة عنصر في مكان ما أعلى شجرة DOM التي نعرف أنها موجودة.

/* ❌ specificity score: 1,0,0 */
#widget {
  /* etc. */
}

/* ✅ specificity score: 0,1,0 */
.page-wrapper :where(#widget) {
  /* etc. */
}

ومع ذلك ، فإن الإشارة إلى عنصر أبوي أمر محفوف بالمخاطر والتقييد. ماذا لو تغيرت فئة الوالدين أو لم تكن موجودة لسبب ما؟ الحل الأفضل (ولكن ربما يكون بنفس القدر من الاختراق) هو استخدام :is() في حين أن. تذكر ، خصوصية :is() يساوي المحدد الأكثر تحديدًا في قائمة المحددات الخاصة به.

لذلك ، بدلاً من الإشارة إلى فصل دراسي نعرف (أو نأمل!) وجوده :where()، كما في المثال أعلاه ، يمكننا الإشارة إلى فئة مكونة و العلامة.

/* ✅ specificity score: 0,1,0 */
:is(.dummy-class, body) :where(#widget) {
  /* etc. */
}

الحاضر دائما body سيساعدنا في اختيار #widget العنصر ووجود .dummy-class فئة داخل نفسه :is() يعطي body محدد نفس درجة الخصوصية مثل فئة (0,1,0) ... واستخدام :where() يضمن أن المحدد لن يكون أكثر تحديدًا من ذلك.

هذا هو!

هذه هي الطريقة التي يمكننا بها الاستفادة من ميزات إدارة الخصوصية الحديثة لـ :is() و :where() الفئات الزائفة جنبًا إلى جنب مع منع الاصطدام النوعي الذي نحصل عليه عند كتابة CSS بتنسيق BEM. وفي المستقبل غير البعيد ، مرة :has() يكتسب دعم Firefox (إنه مدعوم حاليًا خلف علامة في وقت كتابة هذا التقرير) ، من المحتمل أن نرغب في إقرانه بـ: حيث () للتراجع عن خصوصيته.

سواء أكنت تقوم بكل شيء في تسمية BEM أم لا ، آمل أن نتفق على أن الاتساق في خصوصية المحدد أمر جيد!

الطابع الزمني:

اكثر من الخدع المغلق