خصائص CSS المخصصة في The Cascade

نشرت: 2022-03-10
ملخص سريع ↬ في هذه المقالة ، تتعمق ميريام بشكل أعمق في مواصفات "خصائص CSS المخصصة للمتغيرات المتتالية" لتسأل ، "لماذا يطلق عليها الخصائص المخصصة ، وكيف تعمل في التسلسل ، وماذا يمكننا أن نفعل بها أيضًا ؟ " من خلال تجاوز الاستعارة "المتغيرة" ، يمكن للخصائص المخصصة توفير طرق جديدة لموازنة السياق والعزلة في أنماط ومكونات CSS.

في الشهر الماضي ، أجريت محادثة على Twitter حول الفرق بين الأنماط "المحددة النطاق" (التي تم إنشاؤها في عملية الإنشاء) والأنماط "المتداخلة" الأصلية في CSS. سألت لماذا يتجنب المطورون ، حسب الروايات المتناقلة ، خصوصية محددات الهوية ، بينما يتبنون "الأنماط المحددة النطاق" التي تم إنشاؤها بواسطة JavaScript؟ اقترح كيث غرانت أن الاختلاف يكمن في موازنة التسلسل * والميراث ، أي إعطاء الأفضلية للقرب على الخصوصية. لنلقي نظرة.

الشلال

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

  1. يتم تحديد الأهمية من خلال العلامة !important وأصل النمط (المستخدم> المؤلف> المتصفح)
  2. خصوصية المحددات المستخدمة (مضمنة> معرف> فئة> عنصر)
  3. ترتيب المصدر للشفرة نفسها (الأحدث لها الأسبقية)

لم يتم ذكر القرب في أي مكان - علاقة شجرة DOM بين أجزاء المحدد. ستكون كلتا الفقرتين أدناه باللون الأحمر ، على الرغم من أن #inner p يصف علاقة أوثق من #outer p للفقرة الثانية:

راجع القلم [Cascade: Specificity vs Proximity] (https://codepen.io/smashingmag/pen/OexweJ/) بقلم ميريام سوزان.

انظر تسلسل القلم: الخصوصية مقابل القرب من تأليف ميريام سوزان.
 <section> <p>This text is red</p> <div> <p>This text is also red!</p> </div> </section>
 #inner p { color: green; } #outer p { color: red; }

كلا المحددين لهما نفس الخصوصية ، كلاهما يصف نفس العنصر p ، ولا يتم وضع علامة على أي منهما على أنه !important - لذا فإن النتيجة تستند إلى ترتيب المصدر وحده.

المزيد بعد القفز! أكمل القراءة أدناه ↓

أنماط BEM والنطاق

تُستخدم اصطلاحات التسمية مثل BEM ("Block__Element- المُعدِّل") لضمان "تحديد نطاق" كل فقرة لأحد الوالدين فقط ، مع تجنب التتالي تمامًا. يتم إعطاء "عناصر" الفقرة فئات فريدة خاصة بسياق "الكتلة" الخاص بها:

راجع القلم [محددات BEM والتقارب] (https://codepen.io/smashingmag/pen/qzPyeM/) بواسطة Miriam Suzanne.

شاهد محددات القلم BEM والقرب بواسطة ميريام سوزان.
 <section class="outer"> <p class="outer__p">This text is red</p> <div class="inner"> <p class="inner__p">This text is green!</p> </div> </section>
 .inner__p { color: green; } .outer__p { color: red; }

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

راجع القلم [تقارب نمط النطاق] (https://codepen.io/smashingmag/pen/NZaLWN/) بقلم ميريام سوزان.

شاهد القرب من نمط القلم المحدد بواسطة ميريام سوزان.
 <section outer-scope> <p outer-scope>This text is red</p> <div outer-scope inner-scope> <p inner-scope>This text is green!</p> </div> </section>
 p[inner-scope] { color: green } p[outer-scope] { color: red; }

ميراث

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

راجع القلم [الوراثة: الخصوصية مقابل القرب] (https://codepen.io/smashingmag/pen/mZBGyN/) بقلم ميريام سوزان.

انظر وراثة القلم: الخصوصية مقابل القرب لمريم سوزان.
 #inner { color: green; } #outer { color: red; }

نظرًا لأن #inner و #outer يصفان عناصر مختلفة ، فإن div section الخاص بنا على التوالي ، يتم تطبيق كلا خاصيتي اللون دون تعارض. لم يتم تحديد لون العنصر p المتداخل ، لذلك يتم تحديد النتائج بالوراثة (لون الأصل المباشر) بدلاً من التتالي . يكون للتقارب الأسبقية ، وتتجاوز قيمة #inner # جهاز #outer .

ولكن هناك مشكلة: من أجل استخدام الوراثة ، نقوم بتصميم كل شيء داخل section و div . نريد استهداف لون الفقرة على وجه التحديد.

(إعادة) تقديم الخصائص المخصصة

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

راجع القلم [الدعائم المخصصة: الخصوصية مقابل القرب] (https://codepen.io/smashingmag/pen/gNGdaO/) بقلم ميريام سوزان.

راجع الدعائم المخصصة للقلم: الخصوصية مقابل القرب بواسطة ميريام سوزان.
 p { color: var(--paragraph); } #inner { --paragraph: green; } #outer { --paragraph: red; }

ترث خاصية --paragraph تمامًا مثل خاصية color (اللون) ، لكننا الآن نتحكم في كيفية ومكان تطبيق هذه القيمة بالضبط. تعمل خاصية --paragraph بشكل مشابه للمعامل الذي يمكن تمريره إلى المكون p ، إما من خلال التحديد المباشر (قواعد الخصوصية) أو السياق (قواعد التقارب).

أعتقد أن هذا يكشف عن إمكانية وجود خصائص مخصصة نربطها غالبًا بالوظائف أو الخلطات أو المكونات.

"وظائف" ومعلمات مخصصة

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

 html { --stripes: linear-gradient( to right, powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

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

راجع القلم [الدعائم المخصصة: متغير] (https://codepen.io/smashingmag/pen/NZwrrm/) بواسطة ميريام سوزان.

انظر الدعائم المخصصة للقلم: متغيرة بواسطة ميريام سوزان.
 body { background-image: var(--stripes); }

مضيفا المعلمات

تُستخدم الدوال مثل المتغيرات ، لكنها تحدد معلمات لتغيير المخرجات. يمكننا تحديث متغير --stripes بنا ليكون أكثر شبهاً بالوظيفة عن طريق تحديد بعض المتغيرات الشبيهة بالمعامل داخله. سأبدأ بالاستبدال to right بـ var(--stripes-angle) ، لإنشاء معلمة لتغيير الزاوية:

 html { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

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

لا توجد إجابة صحيحة عالمية لهذا التوازن - بعض الوظائف تحتاج إلى أن تكون أكثر مرونة ، والبعض الآخر يحتاج إلى أن يكون أكثر رأيا. توجد التجريدات لتوفير الاتساق وسهولة القراءة في التعليمات البرمجية الخاصة بك ، لذا خذ خطوة للوراء واسأل عن أهدافك. ما الذي يحتاج حقًا إلى أن يكون قابلاً للتخصيص ، وأين يجب تطبيق الاتساق؟ في بعض الحالات ، قد يكون من المفيد أكثر أن يكون لديك وظيفتان عنيدتين ، بدلاً من وظيفة واحدة قابلة للتخصيص بالكامل.

لاستخدام الوظيفة أعلاه ، نحتاج إلى تمرير قيمة --stripes-angle ، وتطبيق الإخراج على خاصية إخراج CSS ، مثل background-image :

 /* in addition to the code above… */ html { --stripes-angle: 75deg; background-image: var(--stripes); } 

راجع القلم [الدعائم المخصصة: الوظيفة] (https://codepen.io/smashingmag/pen/BgwOjj/) بواسطة Miriam Suzanne.

شاهد الدعائم المخصصة للقلم: عمل ميريام سوزان.

موروث مقابل يونيفرسال

لقد حددت دالة --stripes على عنصر html بدافع العادة. ترث الخصائص المخصصة ، وأريد أن تكون وظيفتي متاحة في كل مكان ، لذلك من المنطقي وضعها على عنصر الجذر. يعمل هذا جيدًا لوراثة متغيرات مثل --brand-color: blue ، لذلك قد نتوقع أيضًا أن تعمل مع "وظيفتنا" أيضًا. ولكن إذا حاولنا استخدام هذه الوظيفة مرة أخرى على محدد متداخل ، فلن تعمل:

راجع القلم [الدعائم المخصصة: فشل وراثة الوظيفة] (https://codepen.io/smashingmag/pen/RzjRrM/) بقلم ميريام سوزان.

راجع الدعائم المخصصة للقلم: فشل وراثة الوظيفة لميريام سوزان.
 div { --stripes-angle: 90deg; background-image: var(--stripes); }

يتم تجاهل --stripes-angle الجديدة تمامًا. اتضح أننا لا نستطيع الاعتماد على الوراثة للوظائف التي تحتاج إلى إعادة حساب. هذا لأنه يتم حساب كل قيمة خاصية مرة واحدة لكل عنصر (في حالتنا ، عنصر جذر html ) ، ثم يتم توارث القيمة المحسوبة . من خلال تحديد وظيفتنا في جذر المستند ، لا نجعل الوظيفة بالكامل متاحة للأحفاد - فقط النتيجة المحسوبة لوظيفتنا.

يكون هذا منطقيًا إذا قمت --stripes-angle المتتالية. مثل أي خاصية CSS موروثة ، فهي متاحة للأحفاد وليس للأسلاف. القيمة التي قمنا بتعيينها على div متداخلة غير متاحة للدالة التي حددناها في أصل جذر html . من أجل إنشاء وظيفة متاحة عالميًا والتي ستعيد حساب أي عنصر ، يتعين علينا تحديدها في كل عنصر:

راجع القلم [الدعائم المخصصة: الوظيفة العامة] (https://codepen.io/smashingmag/pen/agLaNj/) بواسطة Miriam Suzanne.

شاهد الدعائم المخصصة للقلم: الوظيفة العامة لميريام سوزان.
 * { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); }

يجعل المحدد العام وظيفتنا متاحة في كل مكان ، ولكن يمكننا تحديدها بشكل أضيق إذا أردنا ذلك. الشيء المهم هو أنه لا يمكنه إعادة الحساب إلا إذا تم تعريفه صراحةً. وهنا بعض البدائل:

 /* make the function available to elements with a given selector */ .stripes { --stripes: /* etc… */; } /* make the function available to elements nested inside a given selector */ .stripes * { --stripes: /* etc… */; } /* make the function available to siblings following a given selector */ .stripes ~ * { --stripes: /* etc… */; } 

راجع القلم [الدعائم المخصصة: وظيفة النطاق] (https://codepen.io/smashingmag/pen/JQMvGM/) بقلم ميريام سوزان.

شاهد الدعائم المخصصة للقلم: وظيفة محددة النطاق بواسطة ميريام سوزان.

يمكن تمديد هذا بأي منطق محدد لا يعتمد على الوراثة.

المعلمات المجانية والقيم الاحتياطية

في المثال أعلاه ، var(--stripes-angle) ليس له قيمة ولا احتياطي. على عكس متغيرات Sass أو JS التي يجب تعريفها أو إنشاء مثيل لها قبل استدعائها ، يمكن استدعاء خصائص CSS المخصصة دون أن يتم تعريفها على الإطلاق. يؤدي هذا إلى إنشاء متغير "مجاني" ، مشابه لمعامل دالة يمكن توريثه من السياق.

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

  1. بالنسبة للمعلمات "المطلوبة" ، لا نريد رجوعًا. كما هي ، لن تفعل الوظيفة شيئًا حتى يتم تحديد --stripes-angle .
  2. بالنسبة للمعلمات "الاختيارية" ، يمكننا توفير قيمة احتياطية في دالة var() . بعد اسم المتغير نضيف فاصلة متبوعة بالقيمة الافتراضية:
 var(--stripes-angle, 90deg)

يمكن أن يكون لكل دالة var() عنصر احتياطي واحد فقط - لذا فإن أي فواصل إضافية ستكون جزءًا من تلك القيمة. هذا يجعل من الممكن توفير الافتراضات المعقدة بفاصلات داخلية:

 html { /* Computed: Hevetica, Ariel, sans-serif */ font-family: var(--sans-family, Hevetica, Ariel, sans-serif); /* Computed: 0 -1px 0 white, 0 1px 0 black */ test-shadow: var(--shadow, 0 -1px 0 white, 0 1px 0 black); }

يمكننا أيضًا استخدام المتغيرات المتداخلة لإنشاء قواعد التسلسل الخاصة بنا ، مع إعطاء أولويات مختلفة للقيم المختلفة:

 var(--stripes-angle, var(--global-default-angle, 90deg))
  1. أولاً ، جرب معاملنا الصريح ( --stripes-angle ) ؛
  2. الرجوع إلى "افتراضي المستخدم" العام ( --user-default-angle ) إذا كان متاحًا ؛
  3. أخيرًا ، الرجوع إلى "إعدادات المصنع الافتراضية" (90deg ).

راجع القلم [الدعائم المخصصة: القيم الاحتياطية] (https://codepen.io/smashingmag/pen/jjGvVm/) بقلم ميريام سوزان.

انظر الدعائم المخصصة للقلم: القيم الاحتياطية بواسطة ميريام سوزان.

من خلال تعيين القيم الاحتياطية في var() بدلاً من تحديد الخاصية المخصصة بشكل صريح ، نضمن عدم وجود قيود محددة أو متتالية على المعلمة. جميع المعلمات *-angle هي "مجانية" ليتم توريثها من أي سياق.

احتياطات المتصفح مقابل الإجراءات الاحتياطية المتغيرة

عندما نستخدم المتغيرات ، هناك مساران احتياطيان يجب أن نضعهما في الاعتبار:

  1. ما هي القيمة التي يجب أن تستخدمها المتصفحات التي لا تحتوي على دعم متغير؟
  2. ما القيمة التي يجب أن تستخدمها المتصفحات التي تدعم المتغيرات ، عندما يكون متغير معين مفقودًا أو غير صالح؟
 p { color: blue; color: var(--paragraph); }

بينما ستتجاهل المتصفحات القديمة خاصية إعلان المتغير ، والعودة إلى blue - ستقرأ المتصفحات الحديثة كليهما وتستخدم الأخير. قد لا يتم تعريف var(--paragraph) الخاصة بنا ، لكنها صالحة وستتجاوز الخاصية السابقة ، لذا فإن المتصفحات ذات الدعم المتغير ستعود إلى القيمة الموروثة أو الأولية ، كما لو كانت unset الكلمة الأساسية غير المحددة.

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

  1. في وقت التحليل ، يتم تجاهل التصريحات التي تحتوي على بناء جملة غير صالح تمامًا - التراجع عن الإعلانات السابقة. هذا هو المسار الذي ستتبعه المتصفحات القديمة. تدعم المتصفحات الحديثة بناء الجملة المتغير ، لذلك يتم تجاهل الإعلان السابق بدلاً من ذلك.
  2. في وقت القيمة المحسوبة ، يتم تصنيف المتغير على أنه غير صالح ، ولكن بعد فوات الأوان - تم تجاهل الإعلان السابق بالفعل. وفقًا للمواصفات ، يتم التعامل مع قيم المتغيرات غير الصالحة بنفس طريقة التعامل مع القيم غير unset :

راجع القلم [الدعائم المخصصة: غير صالح / غير مدعوم مقابل غير محدد] (https://codepen.io/smashingmag/pen/VJMGbJ/) بقلم ميريام سوزان.

راجع الدعائم المخصصة للقلم: غير صالح / غير مدعوم مقابل غير محدد بواسطة ميريام سوزان.
 html { color: red; /* ignored as *invalid syntax* by all browsers */ /* - old browsers: red */ /* - new browsers: red */ color: not a valid color; color: var(not a valid variable name); /* ignored as *invalid syntax* by browsers without var support */ /* valid syntax, but invalid *values* in modern browsers */ /* - old browsers: red */ /* - new browsers: unset (black) */ --invalid-value: not a valid color value; color: var(--undefined-variable); color: var(--invalid-value); }

هذا مفيد أيضًا لنا كمؤلفين ، لأنه يسمح لنا باللعب مع المزيد من الإجراءات الاحتياطية المعقدة للمتصفحات التي تدعم المتغيرات ، وتوفر احتياطيًا بسيطًا للمتصفحات القديمة. والأفضل من ذلك ، يسمح لنا ذلك باستخدام الحالة null / undefined لتعيين المعلمات المطلوبة. يصبح هذا مهمًا بشكل خاص إذا أردنا تحويل دالة إلى مزيج أو مكون.

خاصية مخصصة "Mixins"

في Sass ، تُرجع الدوال قيمًا أولية ، بينما تعيد الخلطات عمومًا مخرجات CSS الفعلية مع أزواج قيمة الخاصية. عندما نحدد خاصية --stripes ، دون تطبيقها على أي ناتج مرئي ، فإن النتيجة تشبه الوظيفة. يمكننا أن نجعل ذلك يتصرف مثل مزيج ، من خلال تحديد الناتج عالميًا أيضًا:

 * { --stripes: linear-gradient( var(--stripes-angle), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

طالما --stripes-angle غير صالحة أو غير محددة ، يفشل التجميع ، ولن يتم تطبيق أي background-image . إذا حددنا زاوية صالحة لأي عنصر ، فستحسب الدالة وتعطينا الخلفية:

 div { --stripes-angle: 30deg; /* generates the background */ }

لسوء الحظ ، سترث قيمة المعلمة هذه ، لذلك يُنشئ التعريف الحالي خلفية عن div وجميع العناصر الفرعية. لإصلاح ذلك ، علينا أن نتأكد من أن قيمة --stripes-angle لا ترث ، عن طريق إراحةها على القيمة initial (أو أي قيمة غير صالحة) على كل عنصر. يمكننا القيام بذلك على نفس المحدد العام:

راجع القلم [الدعائم المخصصة: Mixin] (https://codepen.io/smashingmag/pen/ZdXMJx/) بواسطة Miriam Suzanne.

شاهد الدعائم المخصصة للقلم: Mixin بواسطة Miriam Suzanne.
 * { --stripes-angle: initial; --stripes: /* etc… */; background-image: var(--stripes); }

الأنماط المضمنة الآمنة

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

راجع القلم [الدعائم المخصصة: Mixin + Inline Style] (https://codepen.io/smashingmag/pen/qzPMPv/) بقلم ميريام سوزان.

شاهد الدعائم المخصصة للقلم: Mixin + Inline Style من Miriam Suzanne.
 <div>...</div>

تتميز الأنماط المضمنة بخصوصية عالية ، ومن الصعب جدًا تجاوزها - ولكن مع الخصائص المخصصة ، لدينا خيار آخر: تجاهلها. إذا قمنا بتعيين div إلى background-image: none (على سبيل المثال) لن يكون لهذا المتغير المضمن أي تأثير. لأخذها أبعد من ذلك ، يمكننا إنشاء متغير وسيط:

 * { --stripes-angle: var(--stripes-angle-dynamic, initial); }

الآن لدينا خيار تحديد --stripes-angle-dynamic في HTML ، أو تجاهلها ، وتعيين --stripes-angle مباشرة في ورقة الأنماط الخاصة بنا.

راجع القلم [الدعائم المخصصة: Mixin + Inline / Override] (https://codepen.io/smashingmag/pen/ZdXMao/) بواسطة Miriam Suzanne.

شاهد الدعائم المخصصة للقلم: Mixin + Inline / Override بواسطة Miriam Suzanne.

قيم محددة مسبقا

للقيم الأكثر تعقيدًا ، أو الأنماط الشائعة التي نريد إعادة استخدامها ، يمكننا أيضًا توفير بعض المتغيرات المحددة مسبقًا للاختيار من بينها:

 * { --tilt-down: 6deg; --tilt-up: -6deg; }

واستخدم هذه الإعدادات المسبقة ، بدلاً من تعيين القيمة مباشرةً:

 <div>...</div> 

راجع القلم [الدعائم المخصصة: Mixin + Presets] (https://codepen.io/smashingmag/pen/LKemZm/) بواسطة Miriam Suzanne.

شاهد الدعائم المخصصة للقلم: Mixin + Presets بواسطة Miriam Suzanne.

يعد هذا أمرًا رائعًا لإنشاء المخططات والرسوم البيانية بناءً على البيانات الديناميكية ، أو حتى تخطيط مخطط اليوم.

راجع القلم [مخطط شريطي في شبكة CSS + المتغيرات] (https://codepen.io/smashingmag/pen/wLrEyg/) بواسطة ميريام سوزان.

شاهد مخطط Pen Bar في CSS grid + متغيرات بواسطة Miriam Suzanne.

المكونات السياقية

يمكننا أيضًا إعادة صياغة "mixin" الخاص بنا كـ "مكون" من خلال تطبيقه على محدد صريح ، وجعل المعلمات اختيارية. بدلاً من الاعتماد على وجود - أو عدم وجود --stripes-angle لتبديل ناتجنا ، يمكننا الاعتماد على وجود أو عدم وجود محدد مكون. يسمح لنا ذلك بتعيين القيم الاحتياطية بأمان:

راجع القلم [الدعائم المخصصة: المكون] (https://codepen.io/smashingmag/pen/QXqVmM/) بواسطة Miriam Suzanne.

شاهد الدعائم المخصصة للقلم: مكون من ميريام سوزان.
 [data-stripes] { --stripes: linear-gradient( var(--stripes-angle, to right), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

من خلال وضع العنصر الاحتياطي داخل دالة var() ، يمكننا ترك --stripes-angle غير محددة و "free" لترث قيمة من خارج المكون. هذه طريقة رائعة لفضح جوانب معينة من نمط المكون للمدخلات السياقية. حتى الأنماط "المحددة النطاق" التي تم إنشاؤها بواسطة إطار عمل JS (أو التي تم تحديدها داخل Shadow-DOM ، مثل رموز SVG) يمكنها استخدام هذا الأسلوب لكشف معلمات محددة للتأثير الخارجي.

مكونات معزولة

إذا لم نرغب في الكشف عن المعلمة للوراثة ، فيمكننا تحديد المتغير بقيمة افتراضية:

 [data-stripes] { --stripes-angle: to right; --stripes: linear-gradient( var(--stripes-angle, to right), powderblue 20%, pink 20% 40%, white 40% 60%, pink 60% 80%, powderblue 80% ); background-image: var(--stripes); }

ستعمل هذه المكونات أيضًا مع فئة أو أي محدد صالح آخر ، لكنني اخترت سمة data- لإنشاء مساحة اسم لأي مُعدِّلات نريدها:

 [data-stripes='vertical'] { --stripes-angle: to bottom; } [data-stripes='horizontal'] { --stripes-angle: to right; } [data-stripes='corners'] { --stripes-angle: to bottom right; } 

راجع القلم [الدعائم المخصصة: المكونات المعزولة] (https://codepen.io/smashingmag/pen/agLaGX/) بواسطة ميريام سوزان.

شاهد الدعائم المخصصة للقلم: مكونات معزولة بواسطة ميريام سوزان.

المحددات والمعلمات

غالبًا ما أتمنى أن أتمكن من استخدام سمات البيانات لتعيين متغير - وهي ميزة تدعمها مواصفات CSS3 attr() ، ولكن لم يتم تنفيذها بعد في أي متصفحات (انظر علامة تبويب الموارد للمشكلات المرتبطة في كل متصفح). سيسمح لنا ذلك بربط المحدد بمعامل معين بشكل أوثق:

 <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); } <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); } <div data-stripes="30deg">...</div> /* Part of the CSS3 spec, but not yet supported */ /* attr( , ) */ [data-stripes] { --stripes-angle: attr(data-stripes angle, to right); }

في غضون ذلك ، يمكننا تحقيق شيء مشابه باستخدام سمة style :

راجع القلم [الدعائم المخصصة: محددات النمط] (https://codepen.io/smashingmag/pen/PrJdBG/) بواسطة Miriam Suzanne.

شاهد الدعائم المخصصة للقلم: محددات النمط بواسطة ميريام سوزان.
 <div>...</div> /* The `*=` atttribute selector will match a string anywhere in the attribute */ [style*='--stripes-angle'] { /* Only define the function where we want to call it */ --stripes: linear-gradient(…); }

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

 [style*='--grid-area'] { background-color: white; grid-area: var(--grid-area, auto / 1 / auto / -1); padding: 1em; }

خاتمة

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

هذا يدعونا لإعادة التفكير في العديد من الأدوات التي اعتمدنا عليها في الماضي - من اصطلاحات التسمية مثل SMACSS و BEM ، إلى الأنماط "المحددة" و CSS-in-JS. تساعد العديد من هذه الأدوات في الالتفاف حول الخصوصية ، أو إدارة الأنماط الديناميكية بلغة أخرى - حالات الاستخدام التي يمكننا الآن معالجتها مباشرةً باستخدام الخصائص المخصصة. يمكن الآن معالجة الأنماط الديناميكية التي احتسبناها غالبًا في JS عن طريق تمرير البيانات الأولية إلى CSS.

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

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

قراءة متعمقة

  • "حان الوقت لبدء استخدام خصائص CSS المخصصة ،" سيرج Hospodarets
  • "دليل إستراتيجي لخصائص CSS المخصصة ،" مايكل ريثمولر