كيفية استخدام تطبيق 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 هو شجرة مخفية من العُقد داخل عنصر. وأفضل طريقة لتصور ذلك هي فتح "أداة فحص الويب" وتفعيل الخيار "Show Shadow DOM Tree". بمجرد الانتهاء من ذلك، حاول النظر إلى عنصر إدخال أصلي في عارض - سيكون لديك الآن خيار فتح هذا الإدخال ومشاهدة جميع العناصر بداخله. يمكنك أيضًا تجربة ذلك باستخدام أحد مكونات الويب، جرِّب فحص مكوِّن الإدخال المخصّص للاطّلاع على 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

عندما نعمل على تطوير مكون لنظام التصميم الخاص بنا، فإننا نتبع نهجًا مدروسًا في 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 وميزة البيانات الشاملة. نحن نخطط لتضمين هذه الخصائص المخصّصة السياقية في ملف بيانات البيان هذا.

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


<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.

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