أسماء CSS التي يحدّدها المؤلف وshadow DOM: من الناحية العملية والعملية

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

تسجِّل هذه المقالة الحالة الحالية لسلوك أسماء CSS التي يحدّدها المؤلف على مستوى نطاقات الظل، على أمل أن تُستخدم كمرشد لتحسين إمكانية التشغيل التفاعلي في المستقبل القريب.

ما هي أسماء CSS التي يحدّدها المؤلف؟

أسماء CSS التي يحدّدها المؤلف هي آلية نحوية قديمة نسبيًا في CSS، وقد تمّت إدخالها في الأصل لقاعدة @keyframes التي تحدّد <keyframe-name> على أنّه إما معرّف مخصّص أو سلسلة. الغرض من هذا المفهوم هو تحديد شيء في جزء واحد من جدول الأنماط والإشارة إليه في جزء آخر.

/* "fade-in" is a CSS name, representing a set of keyframes */
@keyframes fade-in {
  from { opacity: 0 };
  to { opacity: 1 }
}

.card {
  /* "fade-in" is a reference to the above keyframes */
  animation-name: fade-in;
}

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

الميزة بيان الاسم مرجع الاسم
الإطارات الرئيسية @keyframes animation-name
الخطوط @font-face { }
@font-palette-values
font-family
font-palette
بيانات المواقع @property
أيّ تعريف خاصية مخصّصة غير مسجَّل
var()
عرض عمليات النقل view-transition-name
view-transition-class
::view-transition-* العناصر الزائفة
موضع الربط anchor-name position-anchor
الصور المتحركة التي يتم تشغيلها من خلال الانتقال للأعلى أو للأسفل view-timeline-name
scroll-timeline-name
animation-timeline
أنماط القوائم @counter-style list-style
العدادات counter-reset
counter-set
counter-increment
طلبات البحث عن الحاويات container-name @container
الصفحة page @page

كما هو موضّح في الجدول، يحتوي اسم CSS عادةً على مرجع CSS متوافق. على سبيل المثال، animation-name هو إشارة إلى اسم @keyframes. تختلف أسماء CSS عن الأسماء المحدّدة في نموذج DOM، مثل السمات وأسماء العلامات، لأنّه يتمّ الإعلان عنها ثمّ الإشارة إليها في سياق جداول الأنماط.

كيفية ارتباط الأسماء بنموذج shadow DOM

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

من خلال الجمع بين أسماء CSS وShadow DOM، من المفترض أن تبدو تجربة إنشاء مكونات الويب تعبيرية بما يكفي لتكون مرنة، ولكن مقيّدة بما يكفي لتكون مستقرة.

هذا أمر جيد من الناحية النظرية. من الناحية العملية، تختلف المتصفحات في طريقة تفاعل أسماء CSS مع shadow DOM، سواء بين الميزات في المتصفّح نفسه أو على مستوى جميع المتصفحات، وبين الميزات والمواصفات.

كيفية عمل الأسماء وShadow DOM معًا

لفهم المشكلة، من المهم معرفة كيفية عمل أجزاء CSS هذه معًا نظريًا.

القاعدة العامة

يتم تحديد القاعدة العامة لكيفية سلوك أسماء CSS في أشجار الظل في مواصفات CSS Scoping Level 1. باختصار: اسم CSS يكون عامًا داخل النطاق الذي تم تحديده فيه، ما يعني أنّه يمكن الوصول إليه من أشجار الظل للعناصر اللاحقة، ولكن ليس من أشجار الظل للعناصر الشقيقين أو العناصر السابقة. يُرجى العلم أنّ هذا يختلف عن الأسماء في منصة الويب، مثل أرقام تعريف العناصر، التي يتم تضمينها ضمن نطاق الشجرة نفسه.

استثناء من القاعدة: @property

على عكس أسماء CSS الأخرى، لا يتم تضمين سمات CSS في عنصر DOM الظلّي. بل هي الطريقة الشائعة لتمرير المَعلمات في أشجار ظل مختلفة. وهذا يجعل وصف @property مميّزًا: من المفترض أن يعمل مثل بيان نوع شامل للمستند يحدد كيفية عمل خاصية مُسمّاة معيّنة. وبما أنّه يجب أن تتطابق الخصائص في أشجار الظل، سيؤدي عدم تطابق تعريفات الخصائص إلى توليد نتائج غير متوقّعة، لذا يتم تحديد تعريفات @property لتتم تسويتها وحلّها وفقًا لترتيب المستند.

آلية عمل القاعدة مع ::part

أجزاء الظل: تعرِض عنصرًا داخل شجرة ظلّ لشجرتها الرئيسية. من خلال إجراء ذلك، يمكن للشجيرة الرئيسية الوصول إلى هذا العنصر وتصميمه أيضًا باستخدام العنصر ::part.

بما أنّ ::part يسمح لنطاقَي شجرة بتنسيق العنصر نفسه، يتم تحديد الترتيب التالي للتسلسل:

  1. أولاً، تحقّق من النمط داخل سياق الظل. هذا هو النمط "التلقائي" للجزء.
  2. بعد ذلك، طبِّق النمط الخارجي كما هو محدّد في ::part. هذا هو النمط "المخصّص" للجزء.
  3. بعد ذلك، طبِّق أيّ نمط داخلي تمّ تحديده مع !important. يسمح ذلك للعنصر المخصّص بتحديد أنّ خاصية معيّنة لجزء معيّن لا يمكن تخصيصها باستخدام ::part.

وهذا يعني أنّه لا يمكن الإشارة إلى الأسماء من داخل shadow DOM من ::part، لأنّ ::part هو أسلوب على مستوى المضيف بدلاً من أسلوب على مستوى الظل. على سبيل المثال:

// inside the shadow DOM:
@keyframes fade-in {
  from { opacity: 0}
}

// This shouldn't work!
// The host style shouldn't know the name "fade-in"
::part(slider) {
  animation-name: fade-in;  
}

آلية عمل القاعدة مع الأنماط المضمّنة

على عكس ::part، يتمّ تطبيق الأنماط المضمّنة التي تحتوي على السمة style، أو التي تضبط النمط باستخدام نصّ برمجي، على النطاق الذي ينطبق عليه العنصر. ويعود السبب في ذلك إلى أنّ تطبيق نمط على عنصر يتطلّب الوصول إلى اسم معرِّف العنصر، وبالتالي إلى جذر الظل نفسه.

كيفية عمل أسماء CSS وShadow DOM معًا في الواقع

على الرغم من أنّ القواعد السابقة محدّدة ومتسقة، لا تعكس عمليات التنفيذ الحالية ذلك دائمًا. من الناحية العملية، يعمل @property بشكل مختلف عن المواصفات بطريقة موحّدة على مستوى المتصفّحات، وتتضمن معظم الميزات الأخرى أخطاء مفتوحة (لم يتم طرح بعض الميزات بعد، لذا يتوفّر الوقت لحلّها).

لاختبار هذه الميزات وشرح كيفية عملها، أنشأنا الصفحة التالية: https://css-names-in-the-shadow.glitch.me/. تحتوي هذه الصفحة على العديد من إطارات iframe، يركز كلّ منها على إحدى الميزات ويختبر ستة سيناريوهات:

  • إشارة خارجية إلى اسم خارجي: لا يتضمّن ذلك DOM الظلّ، ومن المفترض أن يعمل هذا الإجراء بشكلٍ جيد.
  • الإشارة الخارجية إلى اسم داخلي: من المفترض ألا يعمل هذا الإجراء، لأنّ ذلك قد يؤدي إلى تسرُّب الاسم المحدّد في سياق الظل.
  • الإشارة الداخلية إلى الاسم الخارجي: من المفترض أن يكون هذا الإجراء ناجحًا، لأنّ الأسماء على مستوى الشجرة يتم اكتسابها من خلال جذور الظل.
  • الإشارة الداخلية إلى الاسم الداخلي: من المفترض أن يكون هذا صحيحًا، لأنّ اسم الإشارة يقع في النطاق نفسه.
  • ::part يشير إلى الاسم الخارجي: من المفترض أن يعمل هذا الإجراء، لأنّه تمّت الإشارة إلى كلّ من ::part والاسم في النطاق نفسه.
  • ::part الإشارة إلى الاسم الداخلي: من المفترض ألا يعمل هذا الإجراء، لأنّ النطاق الخارجي يجب ألا يحصل على معلومات عن الأسماء التي تمّ الإعلان عنها داخل DOM الظلّ.

@keyframes

وفقًا لما هو محدّد في المواصفات، من المفترض أن تتمكّن من الإشارة إلى أسماء الإطارات الرئيسية من داخل جذر الظل، ما دامت قاعدة at-rule‏ @keyframes في نطاق أحد الأسلاف. من الناحية العملية، لا ينفّذ أي متصفّح هذا السلوك، ولا يمكن الإشارة إلى تعريفات اللقطة الرئيسية إلا في النطاق الذي تم تحديدها فيه. راجِع الطلب 10540.

@property

وكما هو محدّد في المواصفة، سيتم تسطيح أي تعريف لـ @property على مستوى نطاق المستند. في الوقت الحالي، لا يمكنك سوى تعريف @property في نطاق المستند، ويتم تجاهل تعريفات @property ضمن جذور الظل في جميع المتصفّحات.
راجِع المشكلة 10541.

الأخطاء المتعلّقة بالمتصفّح

لا تظهر الميزات الأخرى بشكلٍ متّسق في جميع المتصفّحات:

  • يتم تسطيح @font-face إلى نطاق الجذر في Safari.
  • لا يسمح Chromium بتوريث قواعد anchor-name في جذر الظل
  • لم يتم تحديد نطاق scroll-timeline-name وview-timeline-name بشكل صحيح على ::part (أيضًا في Chromium).
  • لا يسمح أي متصفّح بتعريف @font-palette-values في جذر الظل.
  • يمكن تعريف view-transition-class داخل جذر الظل (يكون الانتقال نفسه خارج جذر الظل).
  • يسمح Firefox لـ ::part بالوصول إلى أسماء الظلال الداخلية (طلبات الحاوية، الصور الرئيسية).
  • لا يمتثل Firefox وSafari لـ @counter-style في جذر الظل.

يُرجى العِلم أنّ counter-reset وcounter-set وcounter-increment لها قواعد مختلفة قليلاً لأنّها أسماء ضمنية، ولأنّ تعريف سمات CSS يعتمد على مجموعة قواعد راسخة تم اختبارها جيدًا.

الخاتمة

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