ارتفاع متحرك - الطريق الصحيح

لنكن صادقين. يمكن أن يكون ارتفاع الرسوم المتحركة معاناة كبيرة. بالنسبة لي ، كانت معركة مستمرة بين الرغبة في الحصول على رسوم متحركة جميلة ، وعدم الاستعداد لدفع تكلفة الأداء الهائلة المرتبطة بتحريك الارتفاع. الآن - كل هذا تم.

بدأ كل شيء عندما كنت أعمل في مشروعي الجانبي - مُنشئ سيرة ذاتية حيث يمكنك مشاركة روابط سيرتك الذاتية التي تكون نشطة فقط لفترة زمنية معينة.

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

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

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

لماذا يجب أن نهتم بالأداء؟

قد يكون من المغري تجاهل الأداء. إنه ليس حكيمًا ، لكنه قد يكون مغريًا. من منظور الأعمال ، يمكنك توفير الكثير من الوقت الذي يمكن إنفاقه في بناء ميزات جديدة.

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

الجانب الآخر من الأداء لا يقل أهمية. نحن ، كمطورين ، نتحمل مسؤولية التأكد من أن الويب يظل متاحًا للجميع - نقوم بذلك لأنه صحيح. لأن الإنترنت ليس لي ولكم فقط ، إنه للجميع.

كما يتضح من مقالة Addy Osmani الممتازة ، تستغرق الأجهزة منخفضة النهاية وقتًا أطول بكثير لتحليل وتنفيذ جافا سكريبت مقارنة بنظيراتها الأعلى.

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

حرك الارتفاع بالطريقة الصحيحة

إذا كنت لا تهتم بالكيفية ، وتريد فقط رؤية مثال حي ، فيرجى الاطلاع على الروابط أدناه الخاصة بالموقع التجريبي ، والأمثلة وحزمة npm للتفاعل:

  • موقع تجريبي يستخدم التقنية
  • مثال حي في Vanilla JS
  • مثال بسيط في رد الفعل
  • حزمة NPM والوثائق للتفاعل

كان السؤال الذي طرحته على نفسي هو كيف يمكنني تجنب تكلفة الأداء التي تتكبدها الرسوم المتحركة للارتفاع. إجابة بسيطة - لا يمكنك ذلك.

بدلاً من ذلك ، كنت بحاجة إلى الإبداع مع خصائص CSS الأخرى التي لا تتحمل هذه التكاليف. وهي تتحول.

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

الطريقة التي سنستخدمها لتحقيق أداء رسوم متحركة للارتفاع هي في الواقع عن طريق تزويرها بالتحويل: scaleY. يتم عمل الرسوم المتحركة في عدة خطوات:

هذا مثال:

 ${this.markup} `
  • نحتاج أولاً إلى الحصول على الارتفاع الأولي لحاوية العنصر. ثم قمنا بتعيين ارتفاع الحاوية الخارجية ليكون صريحًا على هذا الارتفاع. سيؤدي هذا إلى تجاوز أي محتوى متغير الحاوية بدلاً من توسيع نطاقها الرئيسي.
  • داخل الحاوية الخارجية ، لدينا عنصر div آخر تم وضعه تمامًا ليمتد بكامل عرضه وارتفاعه. هذه هي خلفيتنا ، وسيتم تغيير حجمها بمجرد تبديل التحول.
  • لدينا أيضًا حاوية داخلية. تحتوي الحاوية الداخلية على الترميز وستغير ارتفاعها وفقًا للمحتوى الذي تحتوي عليه.
  • إليك الحيلة:  بمجرد تبديل حدث يغير الترميز ، نأخذ الارتفاع الجديد للحاوية الداخلية ونحسب المقدار الذي تحتاجه الخلفية لتلائم الارتفاع الجديد. ثم قمنا بتعيين الخلفية على scaleY بالمبلغ الجديد.
  • في javascript الفانيليا ، هذا يعني بعض الخداع مع العرض المزدوج. مرة واحدة للحصول على ارتفاع الحاوية الداخلية لحساب المقياس. ثم مرة أخرى لتطبيق المقياس على الخلفية div بحيث يتم إجراء التحويل.

يمكنك مشاهدة مثال حي هنا في Vanilla JS.

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

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

ارتفاع متحرك في React

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

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

  • عرض المكتبة على NPM هنا
  • يمكن العثور على الوثائق هنا.

أهم مكونات هذه المكتبة هي AnimateHeight و AnimateHeightContainer. دعونا نفحصهم:

// Inside a React component // handleAnimateHeight is called inside AnimateHeight and is passed the // transitionAmount and optionally selectedId if you pass that as a prop to // AnimateHeight. This means that you can use the transitionAmount to // transition your surrounding content.const handleAnimateHeight = (transitionAmount, selectedId) => { this.setState({ transitionAmount, selectedId }); }; // Takes a style prop, a shouldchange prop and a callback. shouldChange // determines when the AnimateHeight component should trigger, which is // whenever the prop changes. The same prop is used to control which // content to show.  {this.state.open && } {!this.state.open && } 
  • مثال مع نقل المحتوى المحيط

توضح لك الأمثلة المذكورة أعلاه كيفية استخدام AnimateHeight وتشغيل المحتوى المحيط بك يدويًا لضبطه. ولكن ماذا لو كان لديك الكثير من المحتوى ولا تريد القيام بهذه العملية يدويًا؟ في هذه الحالة ، يمكنك استخدام AnimateHeight مع AnimateHeightContainer.

لاستخدام AnimateHeightContainer ، تحتاج إلى تزويد جميع الأطفال ذوي المستوى الأعلى بدعامة تسمى animateHeightId ، والتي يجب أيضًا تمريرها إلى مكونات AnimateHeight:

// Inside React Component const handleAnimateHeight = (transitionAmount, selectedId) => { this.setState({ transitionAmount, selectedId }); }; // AnimateHeight receives the transitionAmount and the active id of the AnimateHeight that fired. {this.state.open &&  {!this.state.open && }  // When AnimateHeight is triggered by state change // this content will move because the animateHeightId // is greater than the id of the AnimateHeight component above I will move I will also move 

كما ترى من هذا المثال ، تتلقى AnimateHeight المعلومات التي تحتاجها لضبط المحتوى عند تشغيل مكون AnimateHeight عن طريق تغيير الحالة.

بمجرد حدوث ذلك ، سيقوم مكون AnimateHeight بتشغيل رد الاتصال وتعيين الخصائص في الحالة. يبدو أن ارتفاعه داخل Animate يبدو كالتالي (مبسط):

// Inside AnimateHeight componentDidUpdate() { if (update) { doUpdate() callback(transitionAmount, this.props.animateHeightId) } } // Equivalent to calling this function: const handleAnimateHeight = (transitionAmount, selectedId) => { this.setState({ transitionAmount, selectedId }); }; handleAnimateHeight(transitionAmount, this.props.animateHeight)

أنت الآن مقدار انتقال المحتوى بالبكسل ومعرف مكون AnimateHeight الذي تم إطلاقه. بمجرد تمرير هذه القيم إلى AnimateHeightContainer ، فإنها ستأخذها وتقوم بنقل المكونات الأخرى داخلها ، بشرط أن تقوم بإعداد animateHeightIds المتزايد على الأطفال ذوي المستوى الأعلى.

المزيد من الأمثلة المتقدمة:

  • Moving surrounding content with AnimateHeightContainer
  • Accordion example

NOTE: If you are using this method to animate height and moving surrounding content, you need to add the transition amount to the height of your page.

Conclusion

You may have noticed in this article that we’re not actually animating height — and calling it that is wrong. You are of course, absolutely right. However, I firmly believe that what we call it does not matter. What matters is that we achieve the desired effect with the lowest possible cost to performance.

While I think I found a way that is better than animating the height property directly, I make no claims to have invented or otherwise thought of something that hasn’t been discovered before. Nor do I judge. Perhaps animating height works for you in your scenario — No problem.

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