Frontend Development

إتقان محددات :has() و :is() في CSS لتنسيق المكونات المعقدة

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

فهم المحدد :is()

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

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


.container h1 {
  color: blue;
}

.container h2 {
  color: blue;
}

.container h3 {
  color: blue;
}

باستخدام :is()، يمكنك اختزال هذا إلى قاعدة واحدة نظيفة:


.container :is(h1, h2, h3) {
  color: blue;
}

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

المغير الكبير: المحدد :has()

إذا كان :is() يتعلق بالتجميع، فإن :has() يتعلق بالسياق. يُشار إلى :has() غالباً باسم "محدد الأب"، وهو يحدد عنصراً إذا كان يحتوي على عنصر واحد على الأقل يطابق المحدد المقدم في حجة. تفتح هذه القدرة عالماً من الحلول المعتمدة بالكامل على CSS للحالات التي كانت تتطلب سابقاً JavaScript.

لننظر إلى مثال عملي: تنسيق مجموعة نموذج (form group) بناءً على ما إذا كان حقل الإدخال الخاص بها صالحاً. تقليدياً، كنت بحاجة إلى مستمع حدث (event listener) على حقل الإدخال لإضافة فئة إلى عنصر النموذج الأب. مع :has()، يحدث هذا تلقائياً:


/* تنسيق التسمية إذا كان حقل الإدخال داخل مجموعة النموذج صالحاً */
.form-group:has(input:valid) .label {
  color: green;
}

/* تنسيق حدود مجموعة النموذج إذا كان حقل الإدخال يحتوي على خطأ */
.form-group:has(input:invalid) {
  border-color: red;
}

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


.card:has(:focus-visible) {
  box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
}

التداخل والمركبات

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


nav li:has(~ .dropdown-menu.open) {
  background-color: #f0f0f0;
}

دعم المتصفحات وأفضل الممارسات

اعتباراً من عام 2024، يتمتع كل من :has() و :is() بدعم واسع في المتصفحات الحديثة، بما في ذلك Chrome و Firefox و Safari و Edge. ومع ذلك، إذا كان يجب عليك دعم المتصفحات القديمة مثل Internet Explorer، ففكر في استخدام إضافات PostCSS مثل postcss-nesting أو العودة إلى حلول JavaScript.

عند استخدام هذه المحددات، ضع أفضل الممارسات التالية في الاعتبار:

  • تجنب التداخل المفرط: بينما يعتبر :has() قوياً، إلا أن المحددات المتداخلة بعمق يمكن أن تصبح صعبة التصحيح.
  • اختبار إمكانية الوصول: تأكد من أن المؤشرات البصرية المضافة عبر :has() لا تعتمد حصرياً على اللون، حيث يمكن أن يؤثر ذلك على المستخدمين ذوي الإعاقات البصرية.
  • الأداء: يمكن أن تكون استعلامات :has() المعقدة مكلفة من الناحية الحسابية. قم بإجراء اختبارات الأداء لأنماطك إذا كنت تبني تطبيقات واسعة النطاق.

الخاتمة

تُعد المحددات :is() و :has() تطوراً كبيراً في قدرات CSS. من خلال السماح بتجميع أفضل وتنسيق سياقي، فإنها تمكّن المطورين من كتابة أوراق أنماط أنظف وأكثر دلالية وأكثر قابلية للصيانة. ومع تصبح هذه الميزات معيارية عبر جميع المنصات، لم يعد إتقانها خياراً بل ضرورة لأي مطور واجهة أمامية يرغب في البقاء في طليعة التطور. اعتمد هذه الأدوات لتقليل اعتمادك على JavaScript وإنشاء واجهات مستخدم أكثر متانة.

Share: