4 الحيل التي ساعدتنا على تحسين الواجهة الأمامية

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


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


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



1. الرسوم المتحركة على SCSS


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


لإنشاء المتزلجون ، استخدمنا مكتبة Swiper . بالنسبة إلى شريط التمرير الأفقي ، فإن استخدام هذه المكتبة له ما يبرره ، نظرًا لأننا نحتاج إلى تقديم الدعم لـ svayp من المستخدم. لكن بالنسبة إلى العمودي الدائري الذي لا نهاية له ، فإن Swiper ليست ضرورية ، فلا يوجد تفاعل من قبل المستخدم. لذلك ، أردنا تكرار نفس الوظيفة باستخدام ميزات CSS فقط.


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


دعنا نحلل استخدام SCSS باستخدام مثال شريط التمرير العمودي.



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


<div class="b-vertical-carousel-slider"> <div class="vertical-carousel-slider-wrapper slider-items"> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> </div> </div> 

نحن نزيل رؤية عناصر الحاوية التي ستتجاوزها ونضع ارتفاع الكتل.


 .b-vertical-carousel-slider { position: relative; overflow: hidden; height: $itemHeight * 3; .vertical-carousel-slider-item { height: $itemHeight; } } 

يتغير حساب الرسوم المتحركة فقط إذا تغير عدد العناصر في الخط دائري. بعد ذلك ، نكتب mixin يأخذ معلمة إدخال واحدة - $itemCount


 @mixin verticalSlideAnimation($itemCount) { } 

في المزيج ، أنشئ إطارًا رئيسيًا لكل عنصر ، واضبط الحالة الأولية له ، واستخدم :nth-child لتحديد الرسوم المتحركة للعنصر.


 for $i from * 1 through $itemCount { $animationName: carousel-item-#{$itemCount}-#{$i}; @keyframes #{$animationName} { 0% { transform: translate3d(0, 0, 0) scale(.95); } } .vertical-carousel-slider-item:nchild(#{$i}) { animation: $stepDuration * $itemCount $animation ease infinite; } } 

علاوة على ذلك ، خلال الرسوم المتحركة ، سنقوم بنقل العناصر فقط على طول المحور y وتغيير مقياس العنصر في المنتصف.


ينص عنصر دائري:


  1. سلام
  2. إزاحة Y
  3. إزاحة Y
  4. Y تعويض مع تناقص

كل عنصر سوف يرتفع مرات $itemCount مرات ، يزيد مرة واحدة وينقص مرة واحدة أثناء الحركة. لذلك ، سنقوم بإنشاء وحساب الرسوم المتحركة لكل من الحركات الصعودية.


 @keyframes #{$animationName} { 0% { transform: translate3d(0, 0, 0) scale(.95); } @for $j from 0 through $itemCount { $isFocusedStep: $i == $j + 2; $isNotPrevStep: $i != $j + 1; $offset: 100% / $itemCount * ($animationTime / $stepDuration); @if ($isFocusedStep) { #{getPercentForStep($j, $itemCount, $offset)} { transform: getTranslate($j - 1) scale(.95); } #{getPercentForStep($j, $itemCount)} { transform: getTranslate($j) scale(1); } #{getPercentForStep($j + 1, $itemCount, $offset)} { transform: getTranslate($j) scale(1); } #{getPercentForStep($j + 1, $itemCount)} { transform: getTranslate($j + 1) scale(.95); } } @else if ($isNotPrevStep) { #{getPercentForStep($j, $itemCount, $offset)} { transform: getTranslate($j - 1) scale(.95); } #{getPercentForStep($j, $itemCount)} { transform: getTranslate($j) scale(.95); } } } } 

يبقى تعريف بعض المتغيرات والوظائف:


  • $animationTime - الحركة بين الوقت
  • $stepDuration - إجمالي وقت التنفيذ لخطوة حركة واحدة ( $animationTime + وقت استراحة الكاروسيل)
  • getPercentForStep($step, $itemCount, $offset) - دالة تُرجع النسبة المئوية للنقطة القصوى لإحدى الولايات.
  • getTranslate($step) - ترجمات العوائد تعتمد على خطوة الحركة

تطبيقات دالة المثال:


 @function getPercentForStep($step, $count, $offset: 0) { @return 100% * $step / $count - $offset; } @function getTranslate($step) { @return translate3d(0, -100% * $step, 0); } 

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


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


أضف div المسؤولة عن الظل.


 <div class="b-vertical-carousel-slider"> <div class="vertical-carousel-slider-wrapper"> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> </div> <div class="vertical-carousel-slider-shadow"></div> </div> 

نحن أسلبه ونضيف الرسوم المتحركة.


 @keyframes shadowAnimation { 0% { opacity: 1; } 80% { opacity: 1; } 90% { opacity: 0; } 100% { opacity: 1; } } .vertical-carousel-slider-shadow { top: $itemHeight; left: 0; right: 0; height: $itemHeight; animation: $stepDuration shadowAnimation ease infinite; } 

في هذه الحالة ، لا تحتاج إلى إنشاء والتفكير في طريقة لتحريك الظل تحت كل عنصر ، فنحن نقوم فقط بتحريك كتلة واحدة ، وله حالتان - مرئي ومخفي


نتيجة لذلك ، لدينا حلقة CSS نقية تنعش مع خصائص محسنة فقط. هذا يتيح للمتصفح استخدام تسريع الأجهزة للتقديم. وبالتالي الربح الملموس مقارنة مع الرسوم المتحركة JS:


  1. عند التمرير على الصفحات ذات الرسوم المتحركة على الأجهزة الضعيفة ، تم تخطي الإطارات بوضوح في الرسوم المتحركة JS ، مع إسقاط FPS إلى 15-20. الرسوم المتحركة CSS حسنت الأشياء بشكل واضح. على هذه الأجهزة ، كان هذا الرقم لا يقل عن 50-55 FPS.
  2. لقد تخلصنا من عمل وحدة خارجية حيث لم يكن مطلوبًا.
  3. سيتم تشغيل الرسوم المتحركة حتى عند تعطيل JS

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


روابط مفيدة



2. استخدام واجهة برمجة تطبيقات التقاطع المراقب


يتم تشغيل الرسوم المتحركة التي لا يراها زائر الموقع في مكان ما بعيدًا عن الأنظار وتحمل وحدة المعالجة المركزية. باستخدام Intersection Observer ، نحدد نوع الرسوم المتحركة المرئية على الشاشة في الوقت الحالي ، ونقوم بتشغيلها فقط.


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


على موقعنا ، يتم تنشيط الرسوم المتحركة فقط عندما يظهر عنصر في منفذ العرض. إذا لم نفعل ذلك ، فستكون الصفحات محملة بالتنفيذ المستمر للرسوم المتحركة التي لا تزال بعيدة عن الأنظار. يسمح لك Intersection Observer API بمراقبة تقاطع العنصر مع الأصل أو نطاق المستند.


مثال التنفيذ


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


إضافة فئة is-paused التعامل مع الأنماط


 .b-vertical-carousel-slider.is-paused { .vertical-carousel-slider-wrapper { .vertical-carousel-slider-item { animation-play-state: paused; } } .vertical-carousel-slider-shadow { animation-play-state: paused; } } 

أي عندما تظهر هذه الفئة ، سيتم إيقاف الرسوم المتحركة مؤقتًا.


الآن نحن نصف منطق إضافة وإزالة هذه الفئة


 if (window.IntersectionObserver) { const el = document.querySelector('.b-vertical-carousel-slider'); const observer = new IntersectionObserver(intersectionObserverCallback); observer.observe(el); } 

هنا أنشأنا مثيل IntersectionObserver ، حدد وظيفة intersectionObserverCallback ، والتي ستعمل عندما تتغير الرؤية.


الآن تحديد intersectionObserverCallback


 function intersectionObserverCallback(entries){ if (entries[0].intersectionRatio === undefined) { return; } helperDOM.toggleClass(el, 'is-paused', entries[0].intersectionRatio <= 0); }; 

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


روابط مفيدة



3. تقديم SVG


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


عندما حددنا أساليب للعمل مع الصور ، كان لدينا خياران أمثلان: تضمين SVG في HTML أو استخدام sprites. استقرنا على التضمين. نقوم بتضمين كود XML لكل صورة مباشرة في كود HTML للصفحات. يؤدي هذا إلى زيادة حجمها قليلاً ، ولكن يتم تقديم SVG مباشرة في المستند.


يواصل العديد من المطورين استخدام برامج SVG sprites. ما هو جوهر الطريقة: يتم تجميع مجموعة من الصور (على سبيل المثال ، الرموز) في لوحة كبيرة من الصور ، تسمى العفريت. عندما تحتاج إلى إظهار أيقونة معينة ، يتم استدعاء العفريت ، وبعد ذلك يتم تقديم إحداثيات القطعة المحددة التي توجد عليها. لقد تم ذلك منذ وقت طويل ، حتى في الإصدار الأول من HTTP. ساعد Sprites بقوة في تخزين الملف وتقليل عدد طلبات الخادم. كان هذا مهمًا لأن العديد من الطلبات المتزامنة أبطأت المتصفح. يعد استخدام SVG sprites عكازًا نموذجيًا تتجاهل به منطق العمل من أجل توفير الموارد. الآن عدد الطلبات ليس مهمًا للغاية ، لذلك نوصي بالتضمين.


بادئ ذي بدء ، فإنه يؤثر إيجابيا على الأداء من وجهة نظر الزائر. يرى كيف يتم تحميل الرموز على الفور ولا يعاني الثواني الأولى بعد تحميل الصفحة. عند استخدام صور sprite أو PNG ، فإن الصفحة التي يتم تحميلها تبطئ قليلاً. يكون هذا أمرًا محسوسًا بشكل خاص إذا قام الزائر بالتمرير على الفور للصفحة المحملة - سينخفض ​​FPS إلى 5-15 على الأجهزة غير العليا. يساعد تضمين SVG في HTML في تقليل زمن انتقال الصفحة (شخصي ، من وجهة نظر العميل) والتخلص من الأفاريز وتخطي الإطار أثناء التحميل.


4. التخزين المؤقت باستخدام Service Worker و HTTP Cache


لا معنى لإعادة تحميل صفحة لم تتغير واستخدام حركة مرور الزوار. هناك العديد من استراتيجيات التخزين المؤقت ، استقرنا على المجموعة الأكثر كفاءة.


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


عندما نظرنا في استراتيجية للتخزين المؤقت ، اخترنا استخدام Service Worker و HTTP Cache في نفس الوقت. لنبدأ مع الأول والأكثر تقدما. Service Worker هو ملف js يمكنه التحكم في صفحته أو ملفه ، واعتراض وتعديل الطلبات ، وكذلك طلبات ذاكرة التخزين المؤقت المبرمجة. إنه بمثابة وكيل بين الموقع والخادم ويحدد سلوكهم في وضع عدم الاتصال. كل هذا يتم على "الجبهة" ، دون توصيل "الخلفية".


عامل الخدمة لديه تقلب هائل. يمكننا برمجة السلوك كما يحلو لنا. على سبيل المثال ، نعلم أن الزائر الذي ذهب إلى الصفحة رقم 1 ، مع وجود احتمال بنسبة 90 ٪ ، سوف يذهب إلى الصفحة رقم 2. نطلب من SW تحميل الصفحة الثانية مع الخلفية عندما لا يزال الزائر في الصفحة الأولى. عندما يذهب إليها ، سيتم تحميل الصفحة على الفور. يمكن استخدامه لمهام مختلفة:


  • مزامنة بيانات الخلفية
  • الآلات الحاسبة دون اتصال
  • مخصص templating
  • رد الفعل على وقت وتاريخ معين.

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


لا يدعم عمال الخدمة جميع المتصفحات ، مثل IE أو Safari أو Chrome قبل الإصدار 40.0. إذا تعذر على الجهاز التعامل معه ، فسيتبع قواعد التخزين المؤقت HTTP Cache. أضفنا رؤوس HTTP التالية إلى الصفحات:


 cache-control: no-cache last-modified: Mon, 06 May 2019 04:26:29 GMT 

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


 if-modified-since: Mon, 06 May 2019 04:26:29 GMT 

في حالة عدم حدوث أي تغييرات ، يتلقى المستعرض استجابة بالكود 304 غير معدّل ويستخدم المحتوى المخزن في ذاكرة التخزين المؤقت. إذا تم إجراء تغييرات على المستند ، فيتم إرجاع الاستجابة بالكود 200 وتتم كتابة استجابة جديدة على تخزين المستعرض.


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


 Cache-control:max-age=31536000, immutable 

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


روابط مفيدة



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


نحن ندعوك إلى فريقنا


نحن نبحث دائمًا عن متخصصين رائعين في مكتبنا في سانت بطرسبرغ للقيام بمهامنا الطموحة: المطورين ، المختبرين ، المصممين. أدناه هناك الشواغر - الانضمام إلينا.


Source: https://habr.com/ru/post/ar455700/


All Articles