تحريك تمويه

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

الملخّص

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

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

المشكلة

يتم تحويل الترميز إلى زخارف بواسطة وحدة المعالجة المركزية (CPU). يتم تحميل الزخارف إلى وحدة معالجة الرسومات. ترسم وحدة معالجة الرسومات هذه الزخارف على المخزن المؤقت للإطارات باستخدام أدوات التظليل. يحدث التمويه في
أداة التظليل.

في الوقت الحالي، لا يمكننا تنفيذ الرسوم المتحركة للتعتيم بشكل فعّال. ومع ذلك، يمكننا العثور على حل يبدو جيدًا بما فيه الكفاية، ولكنه من الناحية الفنية ليس تمويهًا متحرّكًا. للبدء، لنفهم أولاً سبب بطء التمويه المتحرك. هناك أسلوبان لتمويه العناصر على الويب، وهما السمة filter في CSS وفلاتر SVG. وبفضل زيادة الدعم وسهولة الاستخدام، يتم عادةً استخدام فلاتر CSS. لكن للأسف، إذا طُلب منك التوافق مع Internet Explorer، فليس لديك خيار سوى استخدام فلاتر SVG وفقًا للإصدارين 10 و11 من IE الذي يتوافق مع فلاتر CSS هذه، إلا أنه لا يتوافق مع هذه الفلاتر. والخبر السار هو أن الحل البديل لتحريك التمويه يعمل مع كلا الأسلوبين. لذلك دعونا نحاول العثور على المعوقات من خلال الاطلاع على "أدوات مطوري البرامج".

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

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

وهنا تكمن المشكلة، فإننا نستخدم عملية مكلفة لوحدة معالجة الرسومات في كل إطار، مما يؤدي إلى تجاوز ميزانية إطارنا التي تبلغ 16 ملي ثانية، وبالتالي ينتهي الأمر إلى أقل من 60 إطارًا في الثانية.

أسفل حفرة الأرنب

إذًا، كيف يمكننا تنفيذ ذلك بسلاسة؟ يمكننا استخدام بساطة اليد! بدلاً من إضافة حركة لقيمة التمويه الفعلية (نصف قطر التمويه)، نحتسب مسبقًا نسختَين من النُسخ التمويهية حيث تزداد قيمة التمويه بشكل كبير، ثم نحتسب طبقة التلاشي المتقاطع بينهما باستخدام السمة opacity.

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

في تجاربنا، أدى زيادة نصف قطر التمويه بشكل أسّي لكل مرحلة إلى الحصول على أفضل النتائج المرئية. مثال: إذا كانت لدينا أربع مراحل للتمويه، سنطبّق filter: blur(2^n) على كل مرحلة، أي المرحلة 0: 1 بكسل، والمرحلة 1: 2 بكسل، والمرحلة 2: 4 بكسل، والمرحلة 3: 8 بكسل. في حال فرضنا كل نسخة من هذه النُسخ المموّهة على طبقتها الخاصة (المعروفة باسم "الترويج") باستخدام will-change: transform، من المفترض أن يكون تغيير التعتيم في هذه العناصر سريعًا للغاية. نظريًا، سيسمح لنا هذا بتحميل عمل التمويه المكلف مسبقًا. تبين أنّ المنطق معيب. عند تشغيل هذا العرض التوضيحي، سترى أنّ عدد اللقطات في الثانية لا يزال أقل من 60 لقطة في الثانية، وأنّ التمويه أصبح أسوأ من ذي قبل.

أدوات مطوري البرامج
  تعرض تتبُّعًا لفترات طويلة من وقت الانشغال في وحدة معالجة الرسومات.

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

ما توصلنا إليه ليس جميلاً، لكنه يجعل الرسوم المتحركة سريعة للغاية. نحن نعود إلى عدم الترويج للعنصر الذي سيتم تمويهه، بل نروّج بدلاً من ذلك إلى برنامج تضمين رئيسي. إذا تم تعتيم أحد العناصر والترويج له في الوقت نفسه، يتم تطبيق التأثير بواسطة وحدة معالجة الرسومات. وهذا ما جعل العرض التوضيحي بطيئًا. إذا كان العنصر معتمًا ولكن لم يتم الترويج له، فسيتم بدلاً من ذلك بكسلة التمويه إلى أقرب زخرفة رئيسية. وفي حالتنا، يكون هذا هو عنصر برنامج تضمين الأصل الذي تم الترويج له. الصورة المموّهة هي الآن زخرفة من العنصر الأصلي ويمكن إعادة استخدامها لجميع الإطارات المستقبلية. يعمل ذلك فقط لأنّنا نعلم أنّ العناصر المموّهة ليست متحركة، وأنّ تخزينها مؤقتًا أمرٌ مفيد فعلاً. إليك عرض توضيحي لتنفيذ هذا الأسلوب أتساءل ما رأي جهاز Moto G4 في هذا النهج؟ تنبيه بحرق الأحداث: نعتقد أنّ هذا أمر رائع

أدوات مطوري البرامج
  تعرض تتبُّعًا لأوقات عدم النشاط لفترة طويلة في وحدة معالجة الرسومات.

والآن أصبح لدينا مساحة كبيرة على وحدة معالجة الرسومات و60 لقطة في الثانية بسلاسة فائقة. لقد فعلناها!

جارٍ الإنتاج

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

يعتبر معظم المستخدمين أنّ Shadow DOM طريقة لإرفاق العناصر "الداخلية" بالعناصر المخصّصة، إلا أنّه يمثّل أيضًا أسلوبًا أساسيًا للعزلة والأداء. لا يمكن لJavaScript وCSS اختراق حدود Shadow DOM، التي تتيح لنا تكرار المحتوى بدون التأثير في أنماط المطوِّر أو منطق التطبيق. ولدينا بالفعل عنصر <div> لكل نسخة لإجراء مسح نقطي عليها ونستخدم الآن <div> هذه كمضيفات ظل. ننشئ ShadowRoot باستخدام attachShadow({mode: 'closed'}) ونرفِق نسخة من المحتوى إلى ShadowRoot بدلاً من <div> نفسها. علينا أن نتأكد أيضًا من نسخ جميع أوراق الأنماط إلى ShadowRoot لضمان تنسيق النُسخ بالطريقة نفسها التي يتم بها تصميم النُسخ الأصلية.

لا تتوافق بعض المتصفحات مع الإصدار الأول من Shadow DOM، لذا نعود إلى تكرار المحتوى مرة أخرى ونأمل في تحقيق أفضل النتائج بدون انقطاع. كان بإمكاننا استخدام Shadow DOM polyfill مع ShadyCSS، ولكن لم يتم تنفيذ ذلك في مكتبتنا.

ها نحن ذا. بعد رحلتنا إلى أسفل مسار العرض في Chrome، اكتشفنا كيف يمكننا إنشاء تأثيرات حركية فعّالة على مختلف المتصفحات!

الخلاصة

يجب عدم الاستخفاف بهذا النوع من التأثيرات. بما أنّنا ننسخ عناصر DOM ونفرضها على طبقتها الخاصة، يمكننا تجاوز حدود الأجهزة ذات المواصفات المنخفضة. ويشكّل نسخ جميع أوراق الأنماط في كل ShadowRoot خطرًا محتملاً في الأداء أيضًا، لذا عليك تحديد ما إذا كنت تفضّل تعديل المنطق والأنماط لكي لا تتأثر بالنُسخ في LightDOM أو استخدام أسلوب ShadowDOM الخاص بنا. لكن في بعض الأحيان قد تكون تقنيةنا جديرة بالاهتمام. يمكنك إلقاء نظرة على الرمز البرمجي في مستودع جيت هب بالإضافة إلى العرض التوضيحي ومراسلتي على Twitter إذا كانت لديك أي أسئلة.