كيفية استخدام تطبيق Nordhealth للخصائص المخصّصة في مكونات الويب

فوائد استخدام الخصائص المخصصة في أنظمة التصميم ومكتبات المكونات.

David Darnes
David Darnes

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

كيف ننشئ مكونات الويب

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


import {html, css, LitElement} from 'lit';

export class SimpleGreeting extends LitElement {
  static styles = css`:host { color: blue; font-family: sans-serif; }`;

  static properties = {
    name: {type: String},
  };

  constructor() {
    super();
    this.name = 'there';
  }

  render() {
    return html`

Hey ${this.name}, welcome to Web Components!

`
; } } customElements.define('simple-greeting', SimpleGreeting);
عنصر ويب مكتوب باستخدام Lit.

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


// TODO: DevSite - Code sample removed as it used inline event handlers
استخدام مكوّن الويب الذي تم إنشاؤه أعلاه في صفحة:

تغليف نمط Shadow DOM

وبالطريقة نفسها التي تحتوي عناصر HTML الأصلية على Shadow DOM، ينطبق ذلك على مكونات الويب كذلك. Shadow DOM هو شجرة مخفية للعُقد داخل عنصر. وأفضل طريقة لعرض ذلك هي من خلال فتح "أداة فحص الويب" وتفعيل خيار "عرض شجرة Shadow DOM". بعد الانتهاء من ذلك، جرّب البحث عن عنصر إدخال أصلي في أداة الفحص - سيكون لديك الآن خيار فتح هذا الإدخال ومشاهدة جميع العناصر بداخله. يمكنك أيضًا تجربة ذلك باستخدام أحد مكوّنات الويب الخاصة بنا، لذا جرِّب فحص مكوِّن الإدخال المخصّص للاطّلاع على Shadow DOM.

عنصر shadow DOM الذي تم فحصه في "أدوات مطوّري البرامج"
مثال على Shadow DOM في عنصر إدخال نص عادي وفي مكوّن ويب إدخال Nord.

تغليف الأنماط هي إحدى مزايا (أو عيوبها)، حسب مظهرك في Shadow DOM. إذا كتبت CSS في مكوّن الويب، فلا يمكن أن تتسرّب هذه الأنماط وتؤثر على الصفحة الرئيسية أو العناصر الأخرى؛ فهي مضمنة بالكامل داخل المكون. بالإضافة إلى ذلك، فإن CSS المكتوب للصفحة الرئيسية أو مكون الويب الرئيسي لا يمكن أن يتسرب إلى مكون الويب.

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


:host {
  all: unset;
  display: block;
  box-sizing: border-box;
  text-align: start;
  /* ... */
}
رمز نموذجي للمكوّنات يتم تطبيقه على جذر الصورة الرمزية أو أداة اختيار المضيف.

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

وهنا يأتي دور خصائص CSS المخصصة.

الخصائص المخصّصة لصفحات الأنماط المتتالية (CSS)

تم اختيار أسماء الخصائص المخصّصة بشكل مناسب جدًا، فهي خصائص CSS يمكنك تسميتها بنفسك بالكامل وتطبيق أي قيمة مطلوبة عليها. والمطلب الوحيد هو أن تضع واصلتين قبلهما. بعد تحديد السمة المخصّصة، يمكن استخدام القيمة في CSS باستخدام الدالة var().


:root {
  --n-color-accent: rgb(53, 89, 199);
  /* ... */
}

.n-color-accent-text {
  color: var(--n-color-accent);
}
مثال من إطار عمل CSS الخاص بنا للرمز المميّز للتصميم كموقع مخصّص ويتم استخدامه في فئة مساعد.

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

وهذه القدرة على اكتساب الخصائص المخصَّصة باستخدام الوظيفة var() هي طريقة اختراقنا من خلال Shadow DOM لمكوّنات الويب، ومنح المطوّرين إمكانية تحكُّم أكثر دقة عند تصميم المكوّنات.

الخصائص المخصّصة في مكوّن Nord Web Component

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


:root {
  --n-space-m: 16px;
  --n-space-l: 24px;
  /* ... */
  --n-color-background: rgb(255, 255, 255);
  --n-color-border: rgb(216, 222, 228);
  /* ... */
}
يتمّ تحديد "الخصائص المخصّصة لتنسيق CSS" في أداة اختيار الجذر.

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


:host {
  --n-tab-group-padding: 0;
  --n-tab-list-background: var(--n-color-background);
  --n-tab-list-border: inset 0 -1px 0 0 var(--n-color-border);
  /* ... */
}

.n-tab-group-list {
  box-shadow: var(--n-tab-list-border);
  background-color: var(--n-tab-list-background);
  gap: var(--n-space-s);
  /* ... */
}
السمات المخصّصة التي يتم تحديدها في جذر الصورة المظلّلة للمكوّن، ثم استخدامها في أنماط المكوّن ويتم أيضًا استخدام الخصائص المخصَّصة من قائمة الرموز المميّزة للتصميم.

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


.n-tab-group-list::before {
  /* ... */
  padding-inline-start: var(--n-tab-group-padding);
}

.n-tab-group-list::after {
  /* ... */
  padding-inline-end: var(--n-tab-group-padding);
}
السمة المخصّصة السياقية لملء الفراغ في مجموعة علامات التبويب والتي يتم استخدامها في أماكن متعدّدة ضمن رمز المكوّن

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


:host([padding="l"]) {
  --n-tab-group-padding: var(--n-space-l);
}
صيغة مختلفة لمكوّن علامة التبويب حيث يتم تغيير المساحة المتروكة باستخدام تعديل واحد لـ "خاصية مخصّصة" بدلاً من عدة تعديلات.

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


<nord-tab-group label="Title">
  <!-- ... -->
</nord-tab-group>

<style>
  nord-tab-group {
    --n-tab-group-padding: var(--n-space-xl);
  }
</style>
استخدام مكوّن مجموعة علامات التبويب على الصفحة وتعديل خاصية المساحة المخصّصة للمساحة المتروكة إلى حجم أكبر

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

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

تطوير الخصائص المخصَّصة

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

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


<nord-divider></nord-divider>

<section>
  <nord-divider></nord-divider>
   <!-- ... -->
</section>

<style>
  nord-divider {
    --n-divider-color: var(--n-color-status-danger);
  }

  section {
    padding: var(--n-space-s);
    background: var(--n-color-surface-raised);
  }
  
  section nord-divider {
    --n-divider-color: var(--n-color-status-success);
  }
</style>
نسختان من مكوّن المقسم تحتاجان إلى لونَين مختلفَين. أحدهما مُدمَج داخل قسم يمكننا استخدامه لمحدِّد أكثر تحديدًا، ولكن علينا استهداف المقسم على وجه التحديد.

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

الخصائص المخصّصة الخاصة والعامة

السمات المخصّصة الخاصة هي سمات أنشأتها Lea Verou، وهي سمة مخصّصة "خاصة" سياقية في المكوّن نفسه، ولكن تم ضبطها على سمة مخصّصة "عامة" مع قيمة احتياطية.



:host {
  --_n-divider-color: var(--n-divider-color, var(--n-color-border));
  --_n-divider-size: var(--n-divider-size, 1px);
}

.n-divider {
  border-block-start: solid var(--_n-divider-size) var(--_n-divider-color);
  /* ... */
}
ملف CSS الخاص بعنصر الويب المكوّن من المقسم مع خصائص مخصّصة سياقية تم تعديلها لكي يعتمد ملف CSS الداخلي على خاصيّة مخصّصة خاصة تم ضبطها على خاصيّة مخصّصة عامة مع عنصر احتياطي.

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


<nord-divider></nord-divider>

<section>
  <nord-divider></nord-divider>
   <!-- ... -->
</section>

<style>
  nord-divider {
    --n-divider-color: var(--n-color-status-danger);
  }

  section {
    padding: var(--n-space-s);
    background: var(--n-color-surface-raised);
    --n-divider-color: var(--n-color-status-success);
  }
</style>
الفاصلان مرة أخرى، ولكن هذه المرة يمكن إعادة تلوين الفاصل عن طريق إضافة خاصية مخصصة سياقية للفاصل إلى أداة اختيار الأقسام. سيكتسب الفاصل الرمز الخطي نفسه، ما ينتج عنه رمز برمجي أكثر وضوحًا ومرونة.

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

نأمل أن تكون هذه الإحصاءات حول كيفية استخدامنا لمكوّنات الويب مع السمات المخصّصة لتنسيق CSS مفيدة لك. يُرجى إطلاعنا على رأيك وإذا قررت استخدام أي من هذه الطرق في عملك، يمكنك التواصل معي على Twitter @DavidDarnes. يمكنك أيضًا الانتقال إلى حساب Nordhealth @NordhealthHQ على Twitter، بالإضافة إلى باقي أفراد فريقي الذين عملوا بجدّ لدمج نظام التصميم هذا معًا وتنفيذ الميزات المذكورة في هذه المقالة: @Viljamis و@WickyNilliams و@eric_habich.

صورة رئيسية من تصميم دان كريستيان بادوريت