نظرة عامة عملية على CSS Houdini

نشرت: 2022-03-10
ملخص سريع ↬ يهدف Houdini ، وهو مصطلح شامل لمجموعة واجهات برمجة تطبيقات المتصفح ، إلى إدخال تحسينات كبيرة على عملية تطوير الويب وتطوير معايير CSS بشكل عام. سيتمكن مطورو الواجهة الأمامية من توسيع CSS بميزات جديدة باستخدام JavaScript ، والربط بمحرك عرض CSS وإخبار المتصفح بكيفية تطبيق CSS أثناء عملية التقديم. يتحسن دعم متصفح Houdini وبعض واجهات برمجة التطبيقات متاحة للاستخدام اليوم ، لذا فقد حان الوقت للتعرف عليها وتجربتها. سنلقي نظرة على كل جزء من Houdini ، دعم المستعرض الحالي الخاص به ونرى كيف يمكن استخدامه اليوم باستخدام التحسين التدريجي.

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

يتمثل الجانب السلبي المحتمل لاستخدام polyfill في أنه يمكن أن يكون لها تأثير سلبي على الأداء ويصعب تنفيذها بشكل صحيح. يرتبط هذا الجانب السلبي بالمتصفح DOM و CSSOM. ينشئ المستعرض DOM (نموذج كائن المستند) من ترميز HTML ، وبالمثل ، أنشأ CSSOM (نموذج كائن CSS) من ترميز CSS. هاتان الشجرتان الكائنتان مستقلتان عن بعضهما البعض. تعمل JavaScript على DOM ولديها وصول محدود جدًا إلى CSSOM.

تعمل حلول JavaScript Polyfill فقط بعد اكتمال دورة العرض الأولية ، أي عند إنشاء كل من DOM و CSSOM وانتهاء تحميل المستند. بعد أن يقوم Polyfill بإجراء تغييرات على الأنماط في DOM (عن طريق تضمينها) ، فإنه يتسبب في تشغيل عملية العرض مرة أخرى وإعادة عرض الصفحة بأكملها. يصبح التأثير السلبي على الأداء أكثر وضوحًا إذا كانوا يعتمدون على طريقة requestAnimationFrame أو يعتمدون على تفاعلات المستخدم مثل أحداث التمرير.

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

يبدو من المستحيل على مواصفات CSS مواكبة متطلبات الميزات المتنوعة من الصناعة مثل مزيد من التحكم في الرسوم المتحركة ، وتحسين اقتطاع النص ، وخيار تصميم أفضل لعناصر input والتحديد ، والمزيد من select display ، والمزيد من خيارات filter ، إلخ.

ماذا يمكن أن يكون الحل المحتمل؟ امنح المطورين طريقة أصلية لتوسيع CSS باستخدام واجهات برمجة تطبيقات مختلفة . في هذه المقالة ، سنلقي نظرة على كيفية قيام مطوري الواجهة الأمامية بفعل ذلك باستخدام Houdini APIs و JavaScript و CSS. في كل قسم ، سنقوم بفحص كل واجهة برمجة تطبيقات على حدة ، والتحقق من دعم المتصفح وحالة المواصفات الحالية ، ونرى كيف يمكن تنفيذها اليوم باستخدام التحسين التدريجي.

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

ما هو هوديني؟

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

تتكون مواصفات Houdini من مجموعتين من واجهات برمجة التطبيقات - واجهات برمجة التطبيقات عالية المستوى وواجهات برمجة التطبيقات منخفضة المستوى .

ترتبط واجهات برمجة التطبيقات عالية المستوى ارتباطًا وثيقًا بعملية عرض المتصفح (النمط ← التخطيط ← الطلاء ← المركب). هذا يشمل:

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

تشكل واجهات برمجة التطبيقات منخفضة المستوى أساسًا لواجهات برمجة التطبيقات عالية المستوى. هذا يشمل:

  • واجهة برمجة تطبيقات نموذج الكائن المكتوب
  • خصائص وقيم مخصصة API
  • مقاييس الخط API
  • المناضد

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

مستقبل CSS

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

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

واجهة برمجة تطبيقات نموذج الكائن المكتوب

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

 selectedElement.style.fontSize = newFontSize + "px"; // newFontSize = 20 console.log(selectedElement.style.fontSize); // "20px"

تضيف واجهة برمجة تطبيقات نموذج الكائن المكتوب (OM Typed OM) المزيد من المعاني الدلالية لقيم CSS من خلال تعريضها ككائنات JavaScript مكتوبة. إنه يحسن الشفرة ذات الصلة بشكل كبير ويجعلها أكثر أداءً واستقرارًا وقابلية للصيانة. يتم تمثيل قيم CSS بواسطة واجهة CSSUnitValue التي تتكون من قيمة وخاصية وحدة.

 { value: 20, unit: "px" }

يمكن استخدام هذه الواجهة الجديدة مع الخصائص الجديدة التالية:

  • computedStyleMap() : لتحليل الأنماط المحسوبة (غير المضمنة). هذه طريقة لعنصر محدد يجب استدعاؤها قبل التحليل أو استخدام طرق أخرى.
  • attributeStyleMap : لتحليل وتعديل الأنماط المضمنة. هذه خاصية متاحة على عنصر محدد.
 // Get computed styles from stylesheet (initial value) selectedElement.computedStyleMap().get("font-size"); // { value: 20, unit: "px"} // Set inline styles selectedElement.attributeStyleMap.set("font-size", CSS.em(2)); // Sets inline style selectedElement.attributeStyleMap.set("color", "blue"); // Sets inline style // Computed style remains the same (initial value) selectedElement.computedStyleMap().get("font-size"); // { value: 20, unit: "px"} // Get new inline style selectedElement.attributeStyleMap.get("font-size"); // { value: 2, unit: "em"}

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

تعد get and set مجرد مجموعة فرعية صغيرة من جميع الطرق المتاحة المحددة بواسطة Typed OM API. بعضها يشمل:

  • clear : يزيل جميع الأنماط المضمنة
  • delete : يزيل خاصية CSS محددة وقيمتها من الأنماط المضمنة
  • has : إرجاع قيمة منطقية إذا تم تعيين خاصية CSS محددة
  • append : يضيف قيمة إضافية إلى خاصية تدعم قيمًا متعددة
  • إلخ.

كشف الميزة

 var selectedElement = document.getElementById("example"); if(selectedElement.attributeStyleMap) { /* ... */ } if(selectedElement.computedStyleMap) { /* ... */ }

حالة مواصفات W3C

  • مسودة العمل: تم نشرها للمراجعة من قبل المجتمع

دعم المتصفح

جوجل كروم مايكروسوفت إيدج متصفح أوبرا ثعلب النار سفاري
أيد أيد أيد غير مدعوم دعم جزئي (*)

* مدعوم مع "ميزات منصة الويب التجريبية" أو تمكين علامة ميزة أخرى.

مصدر البيانات: هل هوديني جاهز بعد؟

خصائص وقيم مخصصة API

تسمح CSS Properties And Values ​​API للمطورين بتوسيع متغيرات CSS عن طريق إضافة نوع وقيمة أولية وتحديد الوراثة. يمكن للمطورين تحديد خصائص CSS المخصصة عن طريق تسجيلها باستخدام طريقة registerProperty التي تخبر المتصفحات بكيفية نقلها والتعامل مع الرجوع في حالة حدوث خطأ.

 CSS.registerProperty({ name: "--colorPrimary", syntax: "<color>", inherits: false, initialValue: "blue", });

تقبل هذه الطريقة وسيطة إدخال تمثل كائنًا بالخصائص التالية:

  • name : اسم الخاصية المخصصة
  • syntax : يخبر المتصفح بكيفية تحليل خاصية مخصصة. هذه قيم محددة مسبقًا مثل <color> ، <integer> ، <number> ، <length> ، <percentage> ، إلخ.
  • inherits : يخبر المتصفح ما إذا كانت الخاصية المخصصة ترث قيمة الأصل.
  • القيمة initialValue : تخبر القيمة الأولية التي يتم استخدامها حتى يتم تجاوزها ويتم استخدامها كبديل في حالة حدوث خطأ.

في المثال التالي ، يتم تعيين الخاصية المخصصة لنوع <color> . سيتم استخدام هذه الخاصية المخصصة في انتقال التدرج. قد تفكر في أن CSS الحالي لا يدعم انتقالات التدرجات اللونية للخلفية وستكون على صواب. لاحظ كيف يتم استخدام الخاصية المخصصة نفسها في transition ، بدلاً من خاصية background التي يمكن استخدامها في انتقالات background-color العادية.

 .gradientBox { background: linear-gradient(45deg, rgba(255,255,255,1) 0%, var(--colorPrimary) 60%); transition: --colorPrimary 0.5s ease; /* ... */ } .gradientBox:hover { --colorPrimary: red /* ... */ }

لا يعرف المستعرض كيفية التعامل مع انتقال التدرج ، ولكنه يعرف كيفية التعامل مع انتقالات اللون لأن الخاصية المخصصة محددة على أنها نوع <color> . في المتصفح الذي يدعم Houdini ، سيحدث انتقال متدرج عندما يتم تحريك العنصر فوقه. يمكن أيضًا استبدال نسبة موضع التدرج بخاصية CSS المخصصة (مسجلة كنوع <percentage> ) وإضافتها إلى الانتقال بالطريقة نفسها كما في المثال.

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

في التنفيذ المستقبلي لواجهة برمجة التطبيقات هذه ، سيكون من الممكن تسجيل خاصية مخصصة مباشرةً في CSS.

 @property --colorPrimary { syntax: "<color>"; inherits: false; initial-value: blue; }

مثال

يعرض هذا المثال البسيط لون التدرج وانتقال الموضع في حدث التمرير باستخدام خصائص CSS المخصصة المسجلة للون والموضع على التوالي. كود المصدر الكامل متاح في مستودع المثال.

لون متدرج متحرك وموضع باستخدام Custom Properties & Values ​​API. تمت إضافة تأخير لكل خاصية للتأثير في خاصية انتقال CSS. (معاينة كبيرة)

كشف الميزة

 if (CSS.registerProperty) { /* ... */ }

حالة مواصفات W3C

  • مسودة العمل: تم نشرها للمراجعة من قبل المجتمع

دعم المتصفح

جوجل كروم مايكروسوفت إيدج متصفح أوبرا ثعلب النار سفاري
أيد أيد أيد غير مدعوم غير مدعوم

مصدر البيانات: هل هوديني جاهز بعد؟

مقاييس الخط API

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

حالة مواصفات W3C

  • مجموعة الأفكار: لم يتم تقديم مسودة مواصفات في الوقت الحالي

دعم المتصفح

جوجل كروم مايكروسوفت إيدج متصفح أوبرا ثعلب النار سفاري
غير مدعوم غير مدعوم غير مدعوم غير مدعوم غير مدعوم

مصدر البيانات: هل هوديني جاهز بعد؟

المناضد

قبل الانتقال إلى واجهات برمجة التطبيقات الأخرى ، من المهم شرح مفهوم Worklets. Worklets هي برامج نصية يتم تشغيلها أثناء العرض وهي مستقلة عن بيئة JavaScript الرئيسية. هم نقطة امتداد لتقديم المحركات. تم تصميمها للتوازي (مع 2 أو أكثر من الحالات) وخيوط الحيادية ، وقد قللت من الوصول إلى النطاق العالمي ويتم استدعاؤها بواسطة محرك العرض عند الحاجة. يمكن تشغيل Worklets فقط على HTTPS (في بيئة الإنتاج) أو على المضيف المحلي (لأغراض التطوير).

يقدم Houdini Worklets التالية لتوسيع محرك تصيير المستعرض:

  • برنامج Paint Worklet - Paint API
  • برنامج الرسوم المتحركة - الرسوم المتحركة API
  • Worklet - تخطيط API

API الرسام

تسمح واجهة برمجة تطبيقات الرسام للمطورين باستخدام وظائف جافا سكريبت للرسم مباشرة في خلفية العنصر أو حده أو محتواه باستخدام سياق عرض ثنائي الأبعاد ، وهو مجموعة فرعية من واجهة برمجة تطبيقات HTML5 Canvas. تستخدم Paint API لرسم صورة تستجيب ديناميكيًا للتغييرات في CSS (التغييرات في متغيرات CSS ، على سبيل المثال). سيشعر أي شخص على دراية بـ Canvas API بأنه في المنزل تمامًا مع واجهة برمجة تطبيقات الطلاء الخاصة بـ Houdini.

هناك عدة خطوات مطلوبة في تحديد Paint Worklet:

  1. قم بكتابة وتسجيل تطبيق Paint Worklet باستخدام وظيفة registerPaint
  2. قم باستدعاء Worklet في ملف HTML أو ملف JavaScript الرئيسي باستخدام وظيفة CSS.paintWorklet.addModule
  3. استخدم وظيفة paint() في CSS مع اسم Worklet ووسيطات الإدخال الاختيارية.

دعنا نلقي نظرة على وظيفة registerPaint التي تُستخدم لتسجيل Paint Worklet وتحديد وظائفها.

 registerPaint("paintWorketExample", class { static get inputProperties() { return ["--myVariable"]; } static get inputArguments() { return ["<color>"]; } static get contextOptions() { return {alpha: true}; } paint(ctx, size, properties, args) { /* ... */ } });

تتكون وظيفة registerPaint من عدة أجزاء:

  • inputProperties
    مصفوفة من خصائص CSS المخصصة التي سيتعقبها Worklet. تمثل هذه المجموعة تبعيات عمل الطلاء.
  • inputArguments
    مصفوفة من وسيطات الإدخال التي يمكن تمريرها من وظيفة paint من داخل CSS.
  • contextOptions : السماح أو عدم السماح بتعتيم الألوان. إذا تم الضبط على " false " ، فسيتم عرض جميع الألوان بعتامة كاملة.
  • paint : الوظيفة الرئيسية التي توفر الحجج التالية:
    • ctx : سياق رسم ثنائي الأبعاد ، مطابق تقريبًا لسياق الرسم ثنائي الأبعاد لـ Canvas API.
    • size : كائن يحتوي على عرض العنصر وارتفاعه. يتم تحديد القيم من خلال عملية عرض التخطيط. حجم اللوحة القماشية هو نفس الحجم الفعلي للعنصر.
    • properties : متغيرات الإدخال المحددة في خصائص inputProperties
    • args : مصفوفة من وسيطات الإدخال تم تمريرها في دالة paint في CSS

بعد تسجيل Worklet ، يجب استدعاؤه في ملف HTML ببساطة عن طريق توفير مسار للملف.

 CSS.paintWorklet.addModule("path/to/worklet/file.js");

يمكن أيضًا إضافة أي Worklet من عنوان URL خارجي (من شبكة توصيل المحتوى ، على سبيل المثال) مما يجعلها معيارية وقابلة لإعادة الاستخدام.

 CSS.paintWorklet.addModule("https://url/to/worklet/file.js");

بعد استدعاء Worklet ، يمكن استخدامه داخل CSS باستخدام وظيفة paint . تقبل هذه الوظيفة الاسم المسجل لـ Worklet كوسيطة إدخال أولى وكل وسيطة إدخال تليها عبارة عن وسيطة مخصصة يمكن تمريرها إلى Worklet (يتم تعريفها داخل وسيطة inputArguments ). من هذه النقطة ، يحدد المستعرض وقت استدعاء Worklet وأي إجراءات المستخدم وقيمة خصائص CSS المخصصة التي تتغير للاستجابة لها.

 .exampleElement { /* paintWorkletExample - name of the worklet blue - argument passed to a Worklet */ background-image: paint(paintWorketExample, blue); }

مثال

يعرض المثال التالي واجهة برمجة تطبيقات الرسام وقابلية إعادة استخدام Worklet العامة والنمطية. إنه يستخدم ripple Worklet مباشرة من مستودع Google Chrome Labs ويعمل على عنصر مختلف بأنماط مختلفة. كود المصدر الكامل متاح في مستودع المثال.

مثال على تأثير Ripple (يستخدم Ripple Worklet من Google Chrome Labs) (معاينة كبيرة)

كشف الميزة

 if ("paintWorklet" in CSS) { /* ... */ } @supports(background:paint(paintWorketExample)){ /* ... */ }

حالة مواصفات W3C

  • توصية المرشح: مسودة عمل مستقرة جاهزة للتنفيذ

دعم المتصفح

جوجل كروم مايكروسوفت إيدج متصفح أوبرا ثعلب النار سفاري
أيد أيد أيد غير مدعوم غير مدعوم

مصدر البيانات: هل هوديني جاهز بعد؟

واجهة برمجة تطبيقات الرسوم المتحركة

تعمل واجهة برمجة تطبيقات الرسوم المتحركة على توسيع الرسوم المتحركة على الويب بخيارات للاستماع إلى الأحداث المختلفة (التمرير ، والتمرير ، والنقر ، وما إلى ذلك) وتحسين الأداء عن طريق تشغيل الرسوم المتحركة على سلسلة المحادثات المخصصة الخاصة بهم باستخدام Animation Worklet. يسمح لإجراءات المستخدم بالتحكم في تدفق الرسوم المتحركة التي تعمل بطريقة فعالة وغير معوقة.

مثل أي Worklet ، يجب تسجيل Animation Worklet أولاً.

 registerAnimator("animationWorkletExample", class { constructor(options) { /* ... */ } animate(currentTime, effect) { /* ... */ } });

تتكون هذه الفئة من وظيفتين:

  • constructor : يُستدعى عند إنشاء مثيل جديد. تستخدم للإعداد العام.
  • animate : الوظيفة الرئيسية التي تحتوي على منطق الرسوم المتحركة. يقدم وسيطات الإدخال التالية:
    • currentTime : القيمة الزمنية الحالية من الجدول الزمني المحدد
    • effect : مجموعة من التأثيرات التي تستخدمها هذه الرسوم المتحركة

بعد تسجيل Animation Worklet ، يجب تضمينه في ملف JavaScript الرئيسي ، ويجب تحديد الرسوم المتحركة (عنصر ، إطارات رئيسية ، خيارات) ويتم إنشاء الرسوم المتحركة باستخدام المخطط الزمني المحدد. سيتم شرح مفاهيم الخط الزمني وأساسيات الرسوم المتحركة على الويب في القسم التالي.

 /* Include Animation Worklet */ await CSS.animationWorklet.addModule("path/to/worklet/file.js");; /* Select element that's going to be animated */ const elementExample = document.getElementById("elementExample"); /* Define animation (effect) */ const effectExample = new KeyframeEffect( elementExample, /* Selected element that's going to be animated */ [ /* ... */ ], /* Animation keyframes */ { /* ... */ }, /* Animation options - duration, delay, iterations, etc. */ ); /* Create new WorkletAnimation instance and run it */ new WorkletAnimation( "animationWorkletExample" /* Worklet name */ effectExample, /* Animation (effect) timeline */ document.timeline, /* Input timeline */ {}, /* Options passed to constructor */ ).play(); /* Play animation */

تخطيط الجدول الزمني

تستند الرسوم المتحركة على الويب إلى المخططات الزمنية وتعيين الوقت الحالي إلى مخطط زمني للتوقيت المحلي للتأثير . على سبيل المثال ، دعنا نلقي نظرة على الرسوم المتحركة الخطية المتكررة مع 3 إطارات رئيسية (البداية ، الوسط ، الأخيرة) والتي يتم تشغيلها بعد ثانية واحدة من تحميل الصفحة (تأخير) وبمدة 4 ثوان.

قد يبدو الجدول الزمني للتأثير من المثال كما يلي (مع مدة 4 ثوانٍ بدون تأخير):

الجدول الزمني للتأثير (مدة 4 ثوانٍ) Keyframe
0 مللي ثانية أول إطار رئيسي - تبدأ الرسوم المتحركة
2000 مللي ثانية الإطار الرئيسي الأوسط - الرسوم المتحركة قيد التقدم
4000 ملي ثانية الإطار الرئيسي الأخير - ينتهي الرسم المتحرك أو يعيد تعيينه إلى الإطار الرئيسي الأول

من أجل فهم effect.localTime بشكل أفضل ، من خلال تعيين قيمته على 3000 مللي ثانية (مع مراعاة التأخير 1000 مللي ثانية) ، سيتم قفل الرسوم المتحركة الناتجة في الإطار الرئيسي الأوسط في المخطط الزمني (تأخير 1000 مللي ثانية + 2000 مللي ثانية للإطار الرئيسي الأوسط). سيحدث نفس التأثير من خلال تعيين القيمة على 7000 مللي ثانية و 11000 مللي ثانية لأن الرسوم المتحركة تتكرر في فاصل زمني 4000 مللي ثانية (مدة الرسوم المتحركة).

 animate(currentTime, effect) { effect.localTime = 3000; // 1000ms delay + 2000ms middle keyframe }

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

يُظهر الكود التالي تمثيلًا وظيفيًا لرسم خرائط 1: 1 (دالة خطية) لجدول زمني للتأثير على التوقيت المحلي.

 animate(currentTime, effect) { effect.localTime = currentTime; // y = x linear function }
الجدول الزمني ( document.timeline ) التأثير المعين بالتوقيت المحلي Keyframe
startTime + 0 مللي ثانية (الوقت المنقضي) startTime + 0 مللي ثانية أولا
startTime + 1000ms (الوقت المنقضي) startTime + 1000 مللي ثانية (تأخير) + 0 مللي ثانية أولا
startTime + 3000ms (الوقت المنقضي) startTime + 1000ms (تأخير) + 2000ms وسط
startTime + 5000ms (الوقت المنقضي) startTime + 1000ms (تأخير) + 4000ms آخر أولا
startTime + 7000ms (الوقت المنقضي) startTime + 1000ms (تأخير) + 6000ms وسط
startTime + 9000ms (الوقت المنقضي) startTime + 1000ms (تأخير) + 8000ms آخر أولا

لا يقتصر المخطط الزمني على تعيين 1: 1 للتوقيت المحلي للتأثير. تسمح Animation API للمطورين بمعالجة تعيين المخطط الزمني animate وظيفة الحركة باستخدام وظائف JavaScript القياسية لإنشاء مخططات زمنية معقدة. لا يلزم أيضًا أن تتصرف الرسوم المتحركة بالطريقة نفسها في كل تكرار (إذا تكررت الرسوم المتحركة).

لا يجب أن تعتمد الرسوم المتحركة على الجدول الزمني للمستند الذي يبدأ فقط في حساب المللي ثانية من لحظة تحميله. يمكن استخدام إجراءات المستخدم مثل أحداث التمرير كجدول زمني للرسوم المتحركة باستخدام كائن ScrollTimeline . على سبيل المثال ، يمكن أن تبدأ الرسوم المتحركة عندما يقوم المستخدم بالتمرير إلى 200 بكسل ويمكن أن تنتهي عندما يقوم المستخدم بالتمرير إلى 800 بكسل على الشاشة.

 const scrollTimelineExample = new ScrollTimeline({ scrollSource: scrollElement, /* DOM element whose scrolling action is being tracked */ orientation: "vertical", /* Scroll direction */ startScrollOffset: "200px", /* Beginning of the scroll timeline */ endScrollOffset: "800px", /* Ending of the scroll timeline */ timeRange: 1200, /* Time duration to be mapped to scroll values*/ fill: "forwards" /* Animation fill mode */ }); ...

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

مثال

يوضح المثال التالي كيفية تنفيذ المخطط الزمني غير الخطي. يستخدم وظيفة Gaussian المعدلة ويطبق الترجمة والرسوم المتحركة بالتناوب مع نفس الجدول الزمني. كود المصدر الكامل متاح في مستودع المثال.

الرسوم المتحركة التي تم إنشاؤها باستخدام Animation API والتي تستخدم تعيين وقت وظيفة Gaussian المعدل (معاينة كبيرة)

كشف الميزة

 if (CSS.animationWorklet) { /* ... */ }

حالة مواصفات W3C

  • مسودة العمل العام الأولى: جاهزة لمراجعة المجتمع وعرضة لتغيير المواصفات

دعم المتصفح

جوجل كروم مايكروسوفت إيدج متصفح أوبرا ثعلب النار سفاري
دعم جزئي (*) دعم جزئي (*) دعم جزئي (*) غير مدعوم غير مدعوم

* مدعومة مع تمكين علامة "ميزات منصة الويب التجريبية".

مصدر البيانات: هل هوديني جاهز بعد؟

تخطيط API

تسمح واجهة برمجة تطبيقات Layout للمطورين بتوسيع عملية عرض تخطيط المستعرض من خلال تحديد أوضاع تخطيط جديدة يمكن استخدامها في خاصية display CSS. تقدم Layout API مفاهيم جديدة ، وهي معقدة للغاية وتوفر الكثير من الخيارات لتطوير خوارزميات التخطيط المخصصة.

على غرار برامج العمل الأخرى ، يحتاج مخطط Worklet إلى تسجيله وتعريفه أولاً.

 registerLayout('exampleLayout', class { static get inputProperties() { return ['--exampleVariable']; } static get childrenInputProperties() { return ['--exampleChildVariable']; } static get layoutOptions() { return { childDisplay: 'normal', sizing: 'block-like' }; } intrinsicSizes(children, edges, styleMap) { /* ... */ } layout(children, edges, constraints, styleMap, breakToken) { /* ... */ } });

يحتوي سجل Worklet على الطرق التالية:

  • inputProperties
    مصفوفة من خصائص CSS المخصصة التي سيتتبعها Worklet والتي تنتمي إلى عنصر التخطيط الأصل ، أي العنصر الذي يستدعي هذا التخطيط. تمثل هذه المصفوفة تبعيات تمرين التخطيط.
  • childrenInputProperties
    مصفوفة من خصائص CSS المخصصة التي سيتعقبها Worklet والتي تنتمي إلى العناصر الفرعية لعنصر التخطيط الأصل ، أي العناصر الفرعية للعناصر التي تحدد هذا التخطيط.
  • layoutOptions : يحدد خصائص التخطيط التالية:
    • childDisplay : يمكن أن يكون لها قيمة محددة مسبقًا block أو normal . يحدد ما إذا كان سيتم عرض المربعات ككتل أو مضمنة.
    • sizing : يمكن أن يكون له قيمة محددة مسبقًا block-like أو manual . يخبر المتصفح إما بحساب الحجم مسبقًا أو عدم الحساب مسبقًا (ما لم يتم تعيين الحجم بشكل صريح) ، على التوالي.
  • intrinsicSizes : يحدد كيف يتناسب المربع أو محتواه في سياق التخطيط.
    • children : العناصر الفرعية لعنصر تخطيط الأصل ، أي العناصر الفرعية للعنصر الذي يسمي هذا التخطيط.
    • edges : تخطيط حواف المربع
    • styleMap : أنماط OM مكتوبة لمربع
  • layout : الوظيفة الرئيسية التي تؤدي إلى التخطيط.
    • children : العناصر الفرعية لعنصر تخطيط الأصل ، أي العناصر الفرعية للعنصر الذي يسمي هذا التخطيط.
    • edges : تخطيط حواف المربع
    • constraints : قيود التخطيط الرئيسي
    • styleMap : أنماط OM مكتوبة لمربع
    • breakToken : رمز كسر يستخدم لاستئناف التخطيط في حالة ترقيم الصفحات أو الطباعة.

كما هو الحال في Paint API ، يحدد محرك عرض المستعرض متى يتم استدعاء Paint Worklet. يجب فقط إضافته إلى ملف HTML أو ملف JavaScript رئيسي.

 CSS.layoutWorklet.addModule('path/to/worklet/file.js');

وأخيرًا ، يجب الرجوع إليه في ملف CSS

 .exampleElement { display: layout(exampleLayout); }

كيف ينفذ Layout API التخطيط

في المثال السابق ، تم تعريف exampleLayout باستخدام Layout API.

 .exampleElement { display: layout(exampleLayout); }

يُطلق على هذا العنصر اسم التخطيط الأصلي المحاط بحواف التخطيط التي تتكون من الحشوات والحدود وأشرطة التمرير. يتكون تخطيط الأصل من عناصر فرعية تسمى التخطيطات الحالية . التخطيطات الحالية هي العناصر المستهدفة الفعلية التي يمكن تخصيص تخطيطها باستخدام Layout API. على سبيل المثال ، عند استخدام display: flex; على عنصر ما ، يتم تغيير مواضعها الفرعية لتشكيل التخطيط المرن. هذا مشابه لما يتم إجراؤه باستخدام Layout API.

يتكون كل مخطط حالي من مخطط الطفل وهو عبارة عن خوارزمية تخطيط للعنصر LayoutChild (عنصر ، ::before و ::after العناصر الزائفة) و LayoutChild عبارة عن مربع تم إنشاؤه بواسطة CSS يحتوي فقط على بيانات النمط (بدون بيانات تخطيط). يتم إنشاء عناصر LayoutChild تلقائيًا بواسطة محرك عرض المتصفح في خطوة النمط. يمكن أن يقوم Layout Child بإنشاء جزء يقوم بالفعل بتنفيذ إجراءات تصيير التخطيط.

مثال

على غرار مثال Paint API ، يقوم هذا المثال باستيراد Worklet لتخطيط البناء مباشرة من مستودع Google Chrome Labs ، ولكن في هذا المثال ، يتم استخدامه مع محتوى الصورة بدلاً من النص. كود المصدر الكامل متاح في مستودع المثال.

مثال على تخطيط البناء (يستخدم Masonry Worklet بواسطة Google Chrome Labs (معاينة كبيرة)

كشف الميزة

 if (CSS.layoutWorklet) { /* ... */ }

حالة مواصفات W3C

  • مسودة العمل العام الأولى: جاهزة لمراجعة المجتمع وعرضة لتغيير المواصفات

دعم المتصفح

جوجل كروم مايكروسوفت إيدج متصفح أوبرا ثعلب النار سفاري
دعم جزئي (*) دعم جزئي (*) دعم جزئي (*) غير مدعوم غير مدعوم

* مدعومة مع تمكين علامة "ميزات منصة الويب التجريبية".

مصدر البيانات: هل هوديني جاهز بعد؟

هوديني والتعزيز التدريجي

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

  • استخدم ميزة الكشف عن الميزات لمنع الأخطاء.
    توفر كل Houdini API و Worklet طريقة بسيطة للتحقق مما إذا كانت متوفرة في المتصفح. استخدم اكتشاف الميزات لتطبيق تحسينات Houdini فقط على المتصفحات التي تدعمها وتجنب الأخطاء.
  • استخدمه للعرض التقديمي والتحسين البصري فقط.
    يجب أن يتمتع المستخدمون الذين يتصفحون موقعًا إلكترونيًا على متصفح لا يدعم Houdini حتى الآن بالوصول إلى المحتوى والوظائف الأساسية لموقع الويب. لا ينبغي أن تعتمد تجربة المستخدم وعرض المحتوى على ميزات Houdini ويجب أن يكون لها احتياطي موثوق.
  • استفد من احتياطي CSS القياسي.
    على سبيل المثال ، يمكن استخدام خصائص CSS المخصصة العادية كبديل للأنماط المحددة باستخدام Custom Properties & Values ​​API.

ركز على تطوير تجربة مستخدم موقع ويب عالية الأداء وموثوق بها أولاً ثم استخدم ميزات Houdini لأغراض الديكور كتحسين تدريجي.

خاتمة

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

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

سيكون من المثير مشاهدة ما سيأتي به مجتمع المطورين بينما يكتسب Houdini قوة دفع ودعم أفضل للمتصفح. فيما يلي بعض الأمثلة الرائعة لتجارب Houdini API من المجتمع:

  • تجارب CSS Houdini
  • مقدمة تفاعلية لـ CSS Houdini
  • عينات Houdini بواسطة Google Chrome Labs

مراجع

  • مسودات مواصفات W3C Houdini
  • حالة هوديني (Chrome Dev Summit 2018)
  • برنامج Houdini's Animation Worklet - Google Developers
  • مقدمة تفاعلية لـ CSS Houdini