تصميم مكونات الويب باستخدام ورقة أنماط مشتركة
نشرت: 2022-03-10تعد مكونات الويب ميزة جديدة مذهلة للويب ، مما يسمح للمطورين بتحديد عناصر HTML المخصصة الخاصة بهم. عند دمجها مع دليل النمط ، يمكن لمكونات الويب إنشاء واجهة برمجة تطبيقات مكونة ، والتي تسمح للمطورين بإيقاف نسخ ولصق مقتطفات التعليمات البرمجية وبدلاً من ذلك استخدام عنصر DOM فقط. باستخدام Shadow DOM ، يمكننا تغليف مكون الويب ولا داعي للقلق بشأن حروب الخصوصية مع أي ورقة أنماط أخرى على الصفحة.
ومع ذلك ، يبدو حاليًا أن مكونات الويب وأدلة الأنماط متعارضة مع بعضها البعض. من ناحية أخرى ، توفر أدلة الأنماط مجموعة من القواعد والأنماط المطبقة عالميًا على الصفحة وتضمن الاتساق عبر موقع الويب. من ناحية أخرى ، تمنع مكونات الويب مع Shadow DOM أي أنماط عامة من اختراق تغليفها ، وبالتالي منع دليل النمط من التأثير عليها.
مزيد من القراءة على SmashingMag:
- تطبيق أفضل الممارسات في الأنظمة القائمة على المكونات
- كيفية استخدام أقل من معالج CSS المسبق للحصول على أوراق نمط أكثر ذكاءً
- الغوص العميق في Adobe Edge Reflow
لذا ، كيف يمكن أن يتعايش الاثنان ، مع استمرار أدلة الأنماط العالمية في توفير التناسق والأنماط ، حتى لمكونات الويب باستخدام Shadow DOM؟ لحسن الحظ ، هناك حلول تعمل اليوم ، والمزيد من الحلول القادمة ، والتي تمكن أدلة الأنماط العالمية من توفير التصميم لمكونات الويب. (بالنسبة لبقية هذه المقالة ، سأستخدم مصطلح "مكونات الويب" للإشارة إلى العناصر المخصصة باستخدام Shadow DOM.)
ما الذي يجب أن يكون عليه نمط دليل النمط العالمي في مكون الويب؟
قبل مناقشة كيفية الحصول على دليل نمط عالمي لتصميم مكون ويب ، يجب أن نناقش ما يجب أن نحاول تصميمه وما يجب ألا نحاول تصميمه.
بادئ ذي بدء ، تنص أفضل الممارسات الحالية لمكونات الويب على أنه يجب تغليف أحد مكونات الويب ، بما في ذلك أنماطه ، بحيث لا يعتمد على أي موارد خارجية للعمل. يسمح ذلك باستخدامه في أي مكان داخل أو خارج الموقع ، حتى عندما لا يتوفر دليل النمط.
يوجد أدناه مكون ويب بسيط لنموذج تسجيل الدخول يغلف جميع أنماطه.
<template> <style> :host { color: #333333; font: 16px Arial, sans-serif; } p { margin: 0; } p + p { margin-top: 20px; } a { color: #1f66e5; } label { display: block; margin-bottom: 5px; } input[type="text"], input[type="password"] { background-color: #eaeaea; border: 1px solid grey; border-radius: 4px; box-sizing: border-box; color: inherit; font: inherit; padding: 10px 10px; width: 100%; } input[type="submit"] { font: 16px/1.6 Arial, sans-serif; color: white; background: cornflowerblue; border: 1px solid #1f66e5; border-radius: 4px; padding: 10px 10px; width: 100%; } .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <div class="container"> <form action="#"> <p> <label for="username">User Name</label> <input type="text" name="username"> </p> <p> <label for="password">Password</label> <input type="password" name="password"> </p> <p> <input type="submit" value="Login"> </p> <p class="footnote">Not registered? <a href="#">Create an account</a></p> </form> </div> </template> <script> const doc = (document._currentScript || document.currentScript).ownerDocument; const template = doc.querySelector('#login-form-template'); customElements.define('login-form', class extends HTMLElement { constructor() { super(); const root = this.attachShadow({mode: 'closed'}); const temp = document.importNode(template.content, true); root.appendChild(temp); } }); </script>
ملاحظة: تمت كتابة أمثلة التعليمات البرمجية في مواصفات الإصدار 1 لمكونات الويب.
ومع ذلك ، فإن تغليف كل مكون ويب بالكامل سيؤدي حتمًا إلى الكثير من CSS المكررة ، خاصة عندما يتعلق الأمر بإعداد الطباعة وتصميم العناصر الأصلية. إذا أراد أحد المطورين استخدام فقرة أو علامة ربط أو حقل إدخال في مكون الويب الخاص به ، فيجب تصميمه مثل بقية موقع الويب.
إذا قمنا بتغليف جميع الأنماط التي يحتاجها مكون الويب بالكامل ، فسيتم تكرار CSS لتصميم الفقرات وعلامات الربط وحقول الإدخال وما إلى ذلك عبر جميع مكونات الويب التي تستخدمها. لن يؤدي ذلك إلى زيادة تكاليف الصيانة فحسب ، بل سيؤدي أيضًا إلى زيادة أحجام التنزيل للمستخدمين.
بدلاً من تغليف جميع الأنماط ، يجب أن تغلف مكونات الويب أنماطها الفريدة فقط ثم تعتمد على مجموعة من الأنماط المشتركة للتعامل مع أنماط لكل شيء آخر. ستصبح هذه الأنماط المشتركة بشكل أساسي نوعًا من Normalize.css ، والذي يمكن أن تستخدمه مكونات الويب لضمان تصميم العناصر الأصلية وفقًا لدليل النمط.
في المثال السابق ، كان مكوِّن الويب لنموذج تسجيل الدخول يعلن عن الأنماط لفئتيه الفريدين فقط: .container
و .footnote
. ستنتمي بقية الأنماط إلى ورقة الأنماط المشتركة وستعمل على نمط الفقرات وعلامات الربط وحقول الإدخال وما إلى ذلك.
باختصار ، يجب ألا يحاول دليل النمط تصميم مكون الويب ، ولكن بدلاً من ذلك يجب أن يوفر مجموعة من الأنماط المشتركة التي يمكن لمكونات الويب استخدامها لتحقيق مظهر متناسق.
كيف يتم تصميم Shadow DOM باستخدام أوراق الأنماط الخارجية
سمحت المواصفات الأولية لمكونات الويب (المعروفة باسم الإصدار 0) لأي ورقة أنماط خارجية باختراق Shadow DOM من خلال استخدام محددات ::shadow
أو /deep/
CSS. يتيح لك استخدام ::shadow
و /deep/
أن يكون لديك دليل نمط يتغلغل في Shadow DOM وإعداد الأنماط المشتركة ، سواء أراد مكون الويب ذلك أم لا.
/* Style all p tags inside a web components shadow DOM */ login-form::shadow p { color: red; }
مع ظهور أحدث إصدار من مواصفات مكونات الويب (المعروفة باسم الإصدار 1) ، أزال المؤلفون قدرة أوراق الأنماط الخارجية على اختراق ظل DOM ، ولم يقدموا أي بديل. وبدلاً من ذلك ، فقد تغيرت الفلسفة من استخدام التنانين إلى نمط مكونات الويب إلى استخدام الجسور بدلاً من ذلك. بعبارة أخرى ، يجب أن يكون مؤلفو مكونات الويب مسؤولين عن قواعد الأنماط الخارجية المسموح لها بتصميم مكوناتهم ، بدلاً من إجبارهم على السماح لهم بذلك.
لسوء الحظ ، هذه الفلسفة لم تلحق بالويب حقًا حتى الآن ، مما يتركنا في مأزق قليل. لحسن الحظ ، فإن بعض الحلول المتاحة اليوم ، وبعض الحلول القادمة في المستقبل غير البعيد ، ستسمح بورقة أنماط مشتركة لتصميم مكون ويب.
ما يمكنك القيام به اليوم
هناك ثلاث تقنيات يمكنك استخدامها اليوم تسمح لمكون الويب بمشاركة الأنماط: @import
، والعناصر المخصصة ومكتبة مكونات الويب.
باستخدامimport
الطريقة الأصلية الوحيدة اليوم لإحضار ورقة أنماط إلى مكون ويب هي استخدام @import
. على الرغم من أن هذا يعمل ، إلا أنه مضاد للنمط. ومع ذلك ، بالنسبة لمكونات الويب ، فإنها تمثل مشكلة أداء أكبر.
<template> <style> @import "styleguide.css" </style> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- rest of template DOM --> </template>
عادةً ، يعد @import
مضادًا للنمط لأنه يقوم بتنزيل جميع أوراق الأنماط في سلسلة ، بدلاً من تنزيلها بشكل متوازي ، خاصةً إذا كانت متداخلة. في حالتنا ، لا يمكن المساعدة في تنزيل ورقة أنماط واحدة في سلسلة ، لذا من الناحية النظرية يجب أن يكون الأمر جيدًا. ولكن عندما اختبرت ذلك في Chrome ، أظهرت النتائج أن استخدام @import
تسبب في عرض الصفحة لما يصل إلى نصف ثانية بشكل أبطأ من مجرد تضمين الأنماط مباشرة في مكون الويب.
ملاحظة: نظرًا للاختلافات في كيفية عمل polyfill لواردات HTML مقارنةً بواردات HTML الأصلية ، لا يمكن استخدام WebPagetest.org إلا لإعطاء نتائج موثوقة في المتصفحات التي تدعم في الأصل عمليات استيراد HTML (مثل Chrome).
في النهاية ، لا يزال @import
مضادًا للنمط ويمكن أن يمثل مشكلة في الأداء في مكونات الويب. لذا ، فهو ليس حلاً رائعًا.
لا تستخدم Shadow DOM
نظرًا لأن مشكلة محاولة توفير أنماط مشتركة لمكونات الويب تنبع من استخدام Shadow DOM ، فإن إحدى الطرق لتجنب المشكلة تمامًا هي عدم استخدام shadow DOM.
من خلال عدم استخدام Shadow DOM ، ستنشئ عناصر مخصصة بدلاً من مكونات الويب (انظر الجانب أدناه) ، والفرق الوحيد هو عدم وجود الظل DOM والنطاق. سيخضع العنصر الخاص بك لأنماط الصفحة ، ولكن يتعين علينا بالفعل التعامل مع ذلك اليوم ، لذلك لا يوجد شيء لا نعرف كيفية التعامل معه بالفعل. يتم دعم العناصر المخصصة بالكامل بواسطة webcomponentjs polyfill ، الذي يتمتع بدعم متصفح رائع.
تتمثل أكبر فائدة للعناصر المخصصة في أنه يمكنك إنشاء مكتبة أنماط باستخدامها اليوم ، ولا يتعين عليك الانتظار حتى يتم حل مشكلة التصميم المشترك. ونظرًا لأن الاختلاف الوحيد بين مكونات الويب والعناصر المخصصة هو Shadow DOM ، فيمكنك دائمًا تمكين Shadow DOM في عناصرك المخصصة بمجرد توفر حل للتصميم المشترك.
إذا قررت إنشاء عناصر مخصصة ، فكن على دراية ببعض الاختلافات بين العناصر المخصصة ومكونات الويب.
أولاً ، نظرًا لأن أنماط العنصر المخصص تخضع لأنماط الصفحة والعكس صحيح ، ستحتاج إلى التأكد من أن المحددات الخاصة بك لا تسبب أي تعارضات. إذا كانت صفحاتك تستخدم دليل النمط بالفعل ، فاترك أنماط العنصر المخصص في دليل النمط ، واجعل العنصر يخرج DOM المتوقع وبنية الفئة.
من خلال ترك الأنماط في دليل النمط ، ستنشئ مسار ترحيل سلس لمطوريك ، لأنهم يستطيعون الاستمرار في استخدام دليل النمط كما كان من قبل ، ولكن بعد ذلك ينتقلون ببطء إلى استخدام العنصر المخصص الجديد عندما يكونون قادرين على ذلك. بمجرد أن يستخدم الجميع العنصر المخصص ، يمكنك نقل الأنماط إلى داخل العنصر للاحتفاظ بها معًا والسماح بإعادة بناء مكونات الويب بسهولة لاحقًا.
ثانيًا ، تأكد من تغليف أي كود JavaScript داخل تعبير دالة تم استدعاؤه فورًا (IFFE) ، بحيث لا تتدفق أي متغيرات إلى النطاق العام. بالإضافة إلى عدم توفير نطاق CSS ، لا توفر العناصر المخصصة نطاق JavaScript.
ثالثًا ، ستحتاج إلى استخدام وظيفة connectedCallback
الخاصة بالعنصر المخصص لإضافة قالب DOM إلى العنصر. وفقًا لمواصفات مكون الويب ، يجب ألا تضيف العناصر المخصصة عناصر فرعية أثناء وظيفة المُنشئ ، لذلك ستحتاج إلى تأجيل إضافة DOM إلى وظيفة connectedCallback
.
أخيرًا ، لا يعمل عنصر <slot>
خارج الظل DOM. هذا يعني أنه سيتعين عليك استخدام طريقة مختلفة لتوفير طريقة للمطورين لإدراج محتواهم في العنصر المخصص الخاص بك. عادةً ما يستلزم هذا فقط معالجة DOM بنفسك لإدراج محتواها في المكان الذي تريده.
ومع ذلك ، نظرًا لعدم وجود فصل بين Shadow DOM و light DOM مع العناصر المخصصة ، يجب أيضًا أن تكون حريصًا جدًا على عدم تصميم DOM المُدرج ، نظرًا لأنماط العناصر المتتالية الخاصة بك.
<!-- login-form.html --> <template> <style> login-form .container { max-width: 300px; padding: 50px; border: 1px solid grey; } login-form .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template> <script> (function() { const doc = (document._currentScript || document.currentScript).ownerDocument; const template = doc.querySelector('#login-form-template'); customElements.define('login-form', class extends HTMLElement { constructor() { super(); } // Without the shadow DOM, we have to manipulate the custom element // after it has been inserted in the DOM. connectedCallback() { const temp = document.importNode(template.content, true); this.appendChild(temp); } }); })(); </script>
<!-- index.html --> <link rel="stylesheet" href="styleguide.css"> <link rel="import" href="login-form.html"> <login-form></login-form>
من حيث الأداء ، تكون العناصر المخصصة تقريبًا بنفس سرعة عدم استخدام مكونات الويب (أي ربط ورقة الأنماط المشتركة في head
واستخدام عناصر DOM الأصلية فقط). من بين جميع التقنيات التي يمكنك استخدامها اليوم ، هذا هو الأسرع إلى حد بعيد.
جانبا: لا يزال العنصر المخصص مكون ويب لجميع المقاصد والأغراض. يستخدم مصطلح "مكونات الويب" لوصف أربع تقنيات منفصلة: العناصر المخصصة ، وعلامات القوالب ، وواردات HTML و Shadow DOM.
لسوء الحظ ، تم استخدام المصطلح لوصف أي شيء يستخدم أي مجموعة من التقنيات الأربع. وقد أدى ذلك إلى الكثير من الالتباس حول ما يقصده الأشخاص عندما يقولون "مكون الويب". تمامًا كما اكتشف روب دودسون ، وجدت أنه من المفيد استخدام مصطلحات مختلفة عند الحديث عن العناصر المخصصة مع الظل DOM وبدونه.
يميل معظم المطورين الذين تحدثت إليهم إلى ربط مصطلح "مكون الويب" بعنصر مخصص يستخدم الظل DOM. لذلك ، لأغراض هذه المقالة ، قمت بإنشاء تمييز مصطنع بين مكون الويب والعنصر المخصص.
استخدام مكتبة مكونات الويب
حل آخر يمكنك استخدامه اليوم هو مكتبة مكونات الويب ، مثل Polymer أو SkateJS أو X-Tag. تساعد هذه المكتبات في سد ثغرات الدعم الحالي ويمكنها أيضًا تبسيط التعليمات البرمجية اللازمة لإنشاء مكون ويب. كما أنها توفر عادةً ميزات إضافية تجعل كتابة مكونات الويب أسهل.
على سبيل المثال ، يتيح لك Polymer إنشاء مكون ويب بسيط في بضعة أسطر من JavaScript. ومن المزايا الإضافية أن Polymer يوفر حلاً لاستخدام Shadow DOM وورقة أنماط مشتركة. هذا يعني أنه يمكنك إنشاء مكونات ويب اليوم تشارك الأنماط.
للقيام بذلك ، قم بإنشاء ما يسمونه وحدة نمط ، والتي تحتوي على جميع الأنماط المشتركة. يمكن أن تكون إما علامة <style>
بها أنماط مشتركة مضمنة أو علامة <link rel=“import”>
تشير إلى ورقة أنماط مشتركة. في كلتا الحالتين ، قم بتضمين الأنماط في مكون الويب الخاص بك بعلامة <style include>
، ثم يقوم Polymer بتحليل الأنماط وإضافتها كعلامة <style>
مضمنة إلى مكون الويب الخاص بك.
<!-- shared-styles.html --> <dom-module> <!-- Link to a shared style sheet --> <!-- <link rel="import" href="styleguide.css"> --> <!-- Inline the shared styles --> <template> <style> :host { color: #333333; font: 16px Arial, sans-serif; } /* Rest of shared CSS */ </style> </template> </dom-module>
<!-- login-form.html --> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../shared-styles/shared-styles.html"> <dom-module> <template> <!-- Include the shared styles --> <style include="shared-styles"></style> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template> <script> Polymer({ is: 'login-form' }); </script> </dom-module>
الجانب السلبي الوحيد لاستخدام مكتبة هو أنه يمكن أن يؤخر وقت عرض مكونات الويب الخاصة بك. لا ينبغي أن يكون هذا مفاجئًا لأن تنزيل رمز المكتبة ومعالجته يستغرق وقتًا. لا يمكن بدء عرض أي مكونات ويب على الصفحة حتى تنتهي المكتبة من المعالجة.
في حالة Polymer ، يمكن أن يؤخر وقت عرض الصفحة بما يصل إلى نصف ثانية مقارنة بمكونات الويب الأصلية. تكون وحدة النمط التي تتضمن الأنماط أبطأ قليلاً من وحدة النمط التي تربط الأنماط ، كما أن دمج الأنماط مباشرةً في مكون الويب يكون بنفس سرعة استخدام وحدة نمط.
مرة أخرى ، لا يفعل Polymer أي شيء على وجه الخصوص لجعل وقت العرض أبطأ. يستغرق تنزيل مكتبة Polymer ومعالجة جميع ميزاتها الرائعة ، بالإضافة إلى إنشاء جميع روابط القوالب ، بعض الوقت. إنها مجرد مفاضلة يجب عليك إجراؤها لاستخدام مكتبة مكون الويب.
تظهر نتائج اختبارات الأداء أنه باستخدام البوليمر ، ستعرض مكونات الويب ما يصل إلى نصف ثانية أبطأ من مكونات الويب الأصلية.
وعد المستقبل
إذا لم يعمل أي من الحلول الحالية من أجلك ، فلا تقلق. إذا سارت الأمور على ما يرام ، في غضون بضعة أشهر إلى بضع سنوات ، سنكون قادرين على استخدام الأساليب المشتركة باستخدام بعض الأساليب المختلفة.
خصائص مخصصة
الخصائص المخصصة (أو متغيرات CSS ، كما تم تسميتها) هي طريقة لتعيين واستخدام المتغيرات في CSS. هذه الفكرة ليست جديدة على معالجات CSS الأولية ، ولكن كميزة CSS أصلية ، فإن الخصائص المخصصة هي في الواقع أقوى من متغير المعالج المسبق.
للإعلان عن خاصية مخصصة ، استخدم تدوين الخاصية المخصص –my-variable: value
، وقم بالوصول إلى المتغير باستخدام property: var(–my-variable)
. تتالي الخاصية المخصصة مثل أي قاعدة CSS أخرى ، لذلك ترث قيمتها من أصلها ويمكن تجاوزها. التحذير الوحيد للخصائص المخصصة هو أنه يجب الإعلان عنها داخل محدد ولا يمكن التصريح عنها بمفردها ، على عكس متغير المعالج المسبق.
<style> /* Declare the custom property */ html { --main-bg-color: red; } /* Use the custom property */ input { background: var(--main-bg-color); } </style>
الشيء الوحيد الذي يجعل الخصائص المخصصة قوية للغاية هو قدرتها على اختراق الظل DOM. هذه ليست نفس فكرة محددات /deep/
و ::shadow
لأنها لا تفرض طريقها إلى مكون الويب. بدلاً من ذلك ، يجب على مؤلف مكون الويب استخدام الخاصية المخصصة في CSS الخاص به حتى يتم تطبيقه. هذا يعني أنه يمكن لمؤلف مكون الويب إنشاء واجهة برمجة تطبيقات خاصية مخصصة يمكن لمستهلكي مكون الويب استخدامها لتطبيق أنماطهم الخاصة.
<template> <style> /* Declare the custom property API */ :host { --main-bg-color: brown; } .one { color: var(--main-bg-color); } </style> <div class="one">Hello World</div> </template> <script> /* Code to set up my-element web component */ </script> <my-element></my-element> <style> /* Override the custom variable with own value */ my-element { --main-bg-color: red; } </style>
دعم المتصفح للخصائص المخصصة جيد بشكل مدهش. السبب الوحيد الذي يجعله ليس حلاً يمكنك استخدامه اليوم هو أنه لا يوجد polyfill عامل بدون إصدار Custom Elements 1. يعمل الفريق الذي يقف وراء webcomponentjs polyfill حاليًا على إضافته ، ولكن لم يتم إصداره بعد وفي حالة مدمجة ، مما يعني أنه إذا قمت بتجزئة أصولك للإنتاج ، فلا يمكنك استخدامها. مما أفهمه ، من المقرر إطلاقه في وقت ما في وقت مبكر من العام المقبل.
ومع ذلك ، فإن الخصائص المخصصة ليست طريقة جيدة لمشاركة الأنماط بين مكونات الويب. نظرًا لأنه لا يمكن استخدامها إلا للإعلان عن قيمة خاصية واحدة ، سيظل مكون الويب بحاجة إلى تضمين جميع أنماط دليل النمط ، وإن كان ذلك بقيمها مع استبدال المتغيرات.
تعد الخصائص المخصصة أكثر ملاءمة لخيارات التخصيص ، بدلاً من الأنماط المشتركة. لهذا السبب ، فإن الخصائص المخصصة ليست حلاً قابلاً للتطبيق لمشكلتنا.
/ * استخدم الخاصية المخصصة * / input {background: var (–main-bg-color) ؛ } </style>
الشيء الوحيد الذي يجعل الخصائص المخصصة قوية للغاية هو قدرتها على اختراق الظل DOM. هذه ليست نفس فكرة محددات /deep/
و ::shadow
لأنها لا تفرض طريقها إلى مكون الويب. بدلاً من ذلك ، يجب على مؤلف مكون الويب استخدام الخاصية المخصصة في CSS الخاص به حتى يتم تطبيقه. هذا يعني أنه يمكن لمؤلف مكون الويب إنشاء واجهة برمجة تطبيقات خاصية مخصصة يمكن لمستهلكي مكون الويب استخدامها لتطبيق أنماطهم الخاصة.
<template> <style> /* Declare the custom property API */ :host { --main-bg-color: brown; } .one { color: var(--main-bg-color); } </style> <div class="one">Hello World</div> </template> <script> /* Code to set up my-element web component */ </script> <my-element></my-element> <style> /* Override the custom variable with own value */ my-element { --main-bg-color: red; } </style>
دعم المتصفح للخصائص المخصصة جيد بشكل مدهش. السبب الوحيد الذي يجعله ليس حلاً يمكنك استخدامه اليوم هو أنه لا يوجد polyfill عامل بدون إصدار Custom Elements 1. يعمل الفريق الذي يقف وراء webcomponentjs polyfill حاليًا على إضافته ، ولكن لم يتم إصداره بعد وفي حالة مدمجة ، مما يعني أنه إذا قمت بتجزئة أصولك للإنتاج ، فلا يمكنك استخدامها. مما أفهمه ، من المقرر إطلاقه في وقت ما في وقت مبكر من العام المقبل.
ومع ذلك ، فإن الخصائص المخصصة ليست طريقة جيدة لمشاركة الأنماط بين مكونات الويب. نظرًا لأنه لا يمكن استخدامها إلا للإعلان عن قيمة خاصية واحدة ، سيظل مكون الويب بحاجة إلى تضمين جميع أنماط دليل النمط ، وإن كان ذلك بقيمها مع استبدال المتغيرات.
تعد الخصائص المخصصة أكثر ملاءمة لخيارات التخصيص ، بدلاً من الأنماط المشتركة. لهذا السبب ، فإن الخصائص المخصصة ليست حلاً قابلاً للتطبيق لمشكلتنا.
apply القواعد
بالإضافة إلى الخصائص المخصصة ، تحصل CSS أيضًا على قواعد @apply
. تطبيق القواعد عبارة عن مزيج أساسي لعالم CSS. يتم الإعلان عنها بطريقة مشابهة للخصائص المخصصة ولكن يمكن استخدامها للإعلان عن مجموعات من الخصائص بدلاً من قيم الخصائص فقط. تمامًا مثل الخصائص المخصصة ، يمكن أن يتم توريث قيمها وتجاوزها ، ويجب الإعلان عنها داخل محدد حتى تعمل.
<style> /* Declare rule */ html { --typography: { font: 16px Arial, sans-serif; color: #333333; } } /* Use rule */ input { @apply --typography; } </style>
دعم المستعرض لقواعد @apply
غير موجود أساسًا. يدعمه Chrome حاليًا خلف علامة ميزة (لم أتمكن من العثور عليها) ، ولكن هذا يتعلق بها. لا يوجد أيضًا polyfill عامل للسبب نفسه حيث لا يوجد polyfill للخصائص المخصصة. يعمل فريق @apply
أيضًا على إضافة قواعدapply ، جنبًا إلى جنب مع الخصائص المخصصة ، لذلك سيكون كلاهما متاحًا بمجرد إصدار الإصدار الجديد.
على عكس الخصائص المخصصة ، تعد قواعد @apply
حلاً أفضل بكثير لمشاركة الأنماط. نظرًا لأنه يمكنهم إعداد مجموعة من إعلانات الخصائص ، يمكنك استخدامها لإعداد النمط الافتراضي لجميع العناصر الأصلية ثم استخدامها داخل مكون الويب. للقيام بذلك ، يجب عليك إنشاء قاعدة @apply
لكل عنصر أصلي.
ومع ذلك ، لاستهلاك الأنماط ، يجب عليك تطبيقها يدويًا على كل عنصر أصلي ، والذي سيظل يكرر إعلان النمط في كل مكون ويب. على الرغم من أن هذا أفضل من تضمين جميع الأنماط ، إلا أنه ليس مناسبًا جدًا لأنه يصبح نموذجيًا في الجزء العلوي من كل مكون ويب ، والذي يجب عليك تذكر إضافته حتى تعمل الأنماط بشكل صحيح.
/* styleguide.css */ html { --typography: { color: #333333; font: 16px Arial, sans-serif; } --paragraph: { margin: 0; } --label { display: block; margin-bottom: 5px; } --input-text { background-color: #eaeaea; border: 1px solid grey; border-radius: 4px; box-sizing: border-box; color: inherit; font: inherit; padding: 10px 10px; width: 100%; } --input-submit { font: 16px/1.6 Arial, sans-serif; color: white; background: cornflowerblue; border: 1px solid #1f66e5; border-radius: 4px; padding: 10px 10px; width: 100%; } /* And so on for every native element */ }
<!-- login-form.html --> <template> <style> :host { @apply --typography; } p { @apply --paragraph; } label { @apply --label; } input-text { @apply --input-text; } .input-submit { @apply --input-submit; } .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template>
نظرًا للحاجة إلى نموذج معياري شامل ، لا أعتقد أن قواعد @apply
ستكون حلاً جيدًا لمشاركة الأنماط بين مكونات الويب. هم حل رائع لهم ، رغم ذلك.
في Shadow DOM
وفقًا لمواصفات مكون الويب ، تتجاهل المتصفحات أي علامات <link rel=“stylesheet”>
في Shadow DOM ، وتعاملها تمامًا كما لو كانت داخل جزء من المستند. لقد منعنا هذا من القدرة على الارتباط بأي أنماط مشتركة في مكونات الويب الخاصة بنا ، وهو أمر مؤسف - أي حتى قبل بضعة أشهر ، عندما اقترح فريق عمل مكونات الويب أن تعمل علامات <link rel=“stylesheet”>
في الظل DOM. بعد أسبوع واحد فقط من المناقشة ، اتفقوا جميعًا على أنه ينبغي لهم ذلك ، وبعد بضعة أيام أضافوها إلى مواصفات HTML.
<template> <link rel="stylesheet" href="styleguide.css"> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- rest of template DOM --> </template>
إذا كان هذا يبدو أسرع من أن توافق مجموعة العمل على المواصفات ، فهذا لأنه لم يكن اقتراحًا جديدًا. لقد تم اقتراح جعل علامات link
تعمل في ظل DOM بالفعل منذ ثلاث سنوات على الأقل ، ولكنها كانت متراكمة حتى يتمكنوا من التأكد من أنها لم تكن مشكلة في الأداء.
إذا لم يكن قبول الاقتراح مثيرًا بدرجة كافية ، فقد أضاف Chrome 55 (حاليًا Chrome Canary) الوظيفة الأولية لجعل علامات link
تعمل في ظل DOM. يبدو أن هذه الوظيفة قد هبطت في الإصدار الحالي من Chrome. حتى Safari قام بتطبيق الميزة في Safari 18.
تعد القدرة على الارتباط بالأنماط المشتركة الطريقة الأكثر ملاءمة لمشاركة الأنماط بين مكونات الويب. كل ما عليك فعله هو إنشاء علامة link
، وسيتم تصميم جميع العناصر الأصلية وفقًا لذلك ، دون الحاجة إلى أي عمل إضافي.
بالطبع ، ستحدد الطريقة التي ينفذ بها صانعو المتصفح الميزة ما إذا كان هذا الحل قابلاً للتطبيق. لكي يعمل هذا بشكل صحيح ، يجب إلغاء تكرار علامات link
، بحيث تتسبب مكونات الويب المتعددة التي تطلب نفس ملف CSS في طلب HTTP واحد فقط. سيحتاج CSS أيضًا إلى التحليل مرة واحدة فقط ، بحيث لا يضطر كل مثيل لمكون الويب إلى إعادة حساب الأنماط المشتركة ، ولكن بدلاً من ذلك سيعيد استخدام الأنماط المحسوبة.
يقوم Chrome بكلا الأمرين بالفعل. لذلك ، إذا قام جميع صانعي المستعرضات الآخرين بتطبيقها بنفس الطريقة ، فإن link
العلامات التي تعمل في Shadow DOM سيحل بالتأكيد مشكلة كيفية مشاركة الأنماط بين مكونات الويب.
أوراق الأنماط القابلة للإنشاء
قد تجد صعوبة في تصديق ذلك ، نظرًا لأننا لم نحصل عليه حتى الآن ، لكن علامة link
التي تعمل في ظل DOM ليس حلاً طويل المدى. بدلاً من ذلك ، إنه مجرد حل قصير المدى يوصلنا إلى الحل الحقيقي: أوراق أنماط قابلة للإنشاء.
أوراق الأنماط القابلة للإنشاء عبارة عن اقتراح للسماح بإنشاء كائنات StyleSheet
في JavaScript من خلال وظيفة مُنشئ. يمكن بعد ذلك إضافة ورقة الأنماط المُنشأة إلى الظل DOM من خلال واجهة برمجة التطبيقات ، مما يسمح لـ Shadow DOM باستخدام مجموعة من الأنماط المشتركة.
لسوء الحظ ، هذا كل ما يمكنني جمعه من الاقتراح. حاولت العثور على مزيد من المعلومات حول ماهية أوراق الأنماط القابلة للإنشاء من خلال سؤال مجموعة عمل مكونات الويب ، لكنهم أعادوا توجيهي إلى القائمة البريدية لمجموعة عمل CSS التابعة لـ W3C ، حيث سألت مرة أخرى ، لكن لم يرد أحد. لم أستطع حتى معرفة كيفية تقدم الاقتراح ، لأنه لم يتم تحديثه منذ أكثر من عامين.
ومع ذلك ، فإن مجموعة عمل Web Components تستخدمه كحل لمشاركة الأنماط بين مكونات الويب. نأمل أن يتم تحديث الاقتراح أو ستصدر مجموعة عمل مكونات الويب مزيدًا من المعلومات حوله واعتماده. حتى ذلك الحين ، يبدو أن الحل "طويل الأمد" لن يحدث في المستقبل المنظور.
الدروس المستفادة
بعد شهور من البحث والاختبار ، لدي أمل كبير في المستقبل. من المريح معرفة أنه بعد سنوات من عدم وجود حل لمشاركة الأنماط بين مكونات الويب ، هناك أخيرًا إجابات. قد لا يتم إنشاء هذه الإجابات لبضع سنوات أخرى ، لكنها على الأقل موجودة.
إذا كنت ترغب في استخدام دليل نمط مشترك لتصميم مكونات الويب اليوم ، فإما أنه لا يمكنك استخدام Shadow DOM وبدلاً من ذلك إنشاء عناصر مخصصة ، أو يمكنك استخدام مكتبة مكونات الويب التي تدعم polyfill لأنماط المشاركة. كلا الحلين لهما إيجابيات وسلبيات ، لذا استخدم أيهما أفضل لمشروعك.
إذا قررت الانتظار بعض الوقت قبل الخوض في مكونات الويب ، ففي غضون بضع سنوات سيكون لدينا بعض الحلول الرائعة لمشاركة الأنماط فيما بينها. لذا ، استمر في التحقق من كيفية تقدمه.
أشياء لتأخذها بالحسبان
ضع في اعتبارك بعض الأشياء إذا قررت استخدام عناصر مخصصة أو مكونات ويب اليوم.
الأهم من ذلك ، أن مواصفات مكون الويب لا تزال قيد التطوير ، مما يعني أن الأشياء يمكن أن تتغير وستتغير. لا تزال مكونات الويب تمثل حافة النزيف إلى حد كبير ، لذا كن مستعدًا للبقاء على أهبة الاستعداد أثناء تطورك معها.
إذا قررت استخدام Shadow DOM ، فاعلم أنه بطيء جدًا وغير فعال في المتصفحات المتعددة التعبئة. ولهذا السبب ، أنشأ مطورو Polymer تطبيق DOM المظلل وجعلوه افتراضيًا.
Chrome و Opera و Safari مؤخرًا هي المتصفحات الوحيدة التي تدعم إصدار Shadow DOM 0. لا يزال Firefox قيد التطوير ، على الرغم من دعمه للتجربة منذ الإصدار 29. لا تزال Microsoft تفكر فيه لـ Edge ولديها أولوية عالية على خارطة الطريق الخاصة بها.
ومع ذلك ، فإن Shadow DOM الإصدار 0 هو المواصفات القديمة. Shadow DOM الإصدار 1 هو الإصدار الجديد ، ولا يدعمه بشكل كامل سوى Chrome و Safari و Opera. ناهيك عن أن إصدار العناصر المخصصة 0 قد مر بنفس الترقية ، وأن Chrome فقط يدعم الإصدار 1 من العناصر المخصصة بشكل كامل ، بينما تدعمه معاينة Safari الفنية اعتبارًا من الإصدار 17. يحتوي الإصدار 1 من العناصر المخصصة على بعض التغييرات الرئيسية في كيفية كتابة مكونات الويب ، لذا تأكد من فهمك الكامل لما يستتبعه ذلك.
أخيرًا ، يدعم webcomponentjs polyfill فقط تنفيذ الإصدار 0 من Shadow DOM والعناصر المخصصة. سوف يدعم فرع الإصدار 1 من polyfill الإصدار 1 ، ولكن لم يتم إصداره بعد.