חיפוש ]

שיפור ביצועי Frontend, אנימציות וגלילה באתרים

בין אם שמתם לב או לא, בשנים האחרונות סביב נושא האופטימיזציה ושיפור הביצועים של אתרים הוא נושא מאד מדובר. אותה אופטימיזציה מתמקדת בעיקר בזמן הטעינה של אתרים ומתבצעת על ידי הקטנת המשקל הכולל של הקבצים, אופטימיזציה ברמת השרת וטכניקות נוספות.

אבל מה לגבי אופטימיזציה לאחר שהעמוד נטען? בעבר הרחוק לא היו כלים מתאימים בכדי לנתח ביצועים ברמת פרונטאנד (Frontend Performance) והצורך באלו לא היה ברור מאליו. אך הדרך בה אנו ניגשים לרשת השתנתה מהקצה אל הקצה בשנים האחרונות ואחוז מאד נכבד של האוכלוסיה מוצא עצמו משוטט ברשת האינטרנט במכשירי מובייל כאלו ואחרים.

אז אמנם החומרה של מכשירי מובייל השתדרגה בשנים אלו, אך יש לזכור כי ברמת ספציפיקציות חומרה – מכשירי המובייל נחותים משמעותית ממחשבי דסקטופ ולפטופים למינהם ומכאן שביצועי האתר שלכם במכשירים אלו נמוכים יותר ועלולים לגרום תסכול למשתמשים, וגרוע מכך לגרום להם לנטוש את האתר.

ככל שהאתרים שאנו מפתחים מורכבים יותר, אנו צריכים להקפיד יתרה על חווית משתמש נכונה באמצעות אופטימיזציה לאנימציות ולביצועי הגלילה של האתר (Scrolling Performance) בין היתר.

בכדי לעשות זאת אנו נדרשים להשיג תדירות פריימים (Frame Rate) של 60fps כאשר מספר זה דומה בקירוב לקצב הרענון של המסכים באותם מכשירים ובכך לספק ביצועים חלקים ככל האפשר.

במכשירי מובייל, ולעיתים אף בלפטופים ומחשבים נייחים, הדרך לספק ביצועים אלו יכולה להיות מאתגרת, בטח באתרים מורכבים. במאמר זה אנסה להסביר מעט כיצד לגשת לנושא זה באתר שלכם ולשפר את ביצועי ה Frontend.

נושא זה רחב ויש הרבה מה לומר עליו, אך אנסה לשמור על פוקוס במדריך זה ולהסביר בצורה ישירה דרך אחת לשפר ביצועי Frontend בדגש על ביצועי הגלילה באתרים.

על ביצועי Frontend ופעולת ה Repainting בדפדפנים

אם אתם משנים layout, כלומר משנים מיקום של אלמנטים בעמוד, אז הדפדפן ייאלץ לבצע עבודה בכדי לצבוע מחדש את הפיקסלים על המסך, פעולה הנקראית repainting.

repaint מתרחש בכל שינוי תכונה לאלמנט בעמוד שאינו שינוי opacity או transform אם אינני טועה. כאשר הדפדפן משנה layout הוא תמיד יבצע צביעה מחדש וזאת מכיוון וכל שינוי גיאומטרי של אלמנט משמעו פיקסלים שצריכים להשתנות.

במרבית המקרים, פעולת ״סידור״ הפיקסלים על המסך שלכם היא הפעולה שדורשת הכי הרבה זמן בצינור ועקרונית יש להמנע מזו כמה שניתן.

אם נעזר בתמונות שגוגל סיפקו לנו, העבודה שהדפדפן מבצע (אותו צינור עליו אנו מדברים) מתבצע בצורה הבאה:

triggering layout and paint

אגב, ישנם מצבים בהם אנו משנים תכונות שאינן גיאומטריות כגון שינוי רקעים (backgrounds) שינוי צבע טקסט, הצללות וכדומה. במצבים אלו אין צורך בביצוע תהליך ה layout והצינור ייראה בצורה הבאה:

frame-no-layout

שימוש ב Chrome Dev Tools לזיהוי צוואר הבקבוק של פעולת ה Repainting

ניתן להשתמש בכלי המפתחים של כרום (Chrome Developer Tools) על מנת לזהות במהירות איזורים שנצבעים באתר שלכם מחדש. גשו לכלי המפתחים ופיתחו את הלשונית Rendering. לאחר מכן בחרו את האפשרות "Show paint rectangles" כבתמונה הבאה:

Paint Flashing - Chrome Dev Tools

כאשר אפשרות זו מופעלת, כרום תצבע בירוק מהבהב איזורים אשר נצבעים מחדש (Repainting). גללו את העמוד באתר שלכם כאשר אופציה זו מופעלת ואני מניח שתגלו מספר אלמנטים שנצבעים מחדש במהלך הגלילה ולמרות שבמבט ראשוני, אין זה ברור מדוע איזורים אלו נצבעים מחדש. אם גיליתם כי ישנם איזורים כאלו, תאלצו לחקור קצת ולבדוק מדוע אלו נצבעים מחדש שוב ושוב.

בואו ניתן דוגמה בכדי להבין טוב יותר על מה מדובר ונסתכל על סאבי בלוג. הנה וידאו המראה אילו איזורים נצבעים מחדש כאשר אני מבצע גלילה באתר (זה כבר לא המקרה לאחר האופטימיזציה):

 

שימו לב למספר דברים שרואים בוידאו במהלך הגלילה:

  • חלקו העליון של העמוד (header) נצבע בירוק.
  • כפתורי השיתוף בימין נצבעים בירוק.
  • הבוקסה עם מאמר נוסף (בתחתית העמוד צד שמאל) נצבעת בירוק.

כל החלקים הללו נצבעים מחדש ומעמיסים על הדפדפן בכל פעם שמשתמש מבצע גלילה באתר. יש לכם רעיון מה משותף לשלושתם? אני מניח שניחשתם… לכולם התכונה position:fixed.

אם נתקלתם במצבים בהם הגלילה אינה חלקה וישנן מעין ״תקיעות״ תוך כדי גלילה, כנראה שבאתרים אלו פעולת ה Repainting כבדה. כפי שציינו, זה יכול להיות מפאת אלמנטים הנמצאים כ fixed , אנימציות כאלו ואחרת וכדומה.

אז כמובן שאיננו מעוניינים לשנות את העיצוב של האתר שלנו בגלל אותן תקיעות, אז בואו נראה דרך כיצד לסדר אותן בכדי ליצור גלילה חלקה יותר. יכול להיות גם שלרבים לא אכפת מביצועי Frontend, אך כמפתח וורדפרס השם דגש על ביצועים, מאד מפריע לי כשאני נתקל באתר בו אני חווה תקיעות אלו.

בואו נראה כיצד ניתן להמנע ממצבים (פוטנציאלים) של בעיות גלילה ואנימציות על ידי יצירת שכבות חדשות עבור אלמנטים מסויימים.

הרעיון הוא להגיע למצב בו אידיאלית האתר עובד על 60FPS. ככל שמספר הפריימים לשנייה נמוך יותר הסיכוי שתחוו תקיעות באנימציות ובגלילה גבוהות יותר. לא נרחיב על נושא זה אך אתם מוזמנים להבין איך מודדים פריימים במאמר הבא.

יצירת שכבות (layers) חדשות עבור אותם אלמנטים

אין חובה על הדפדפן להתייחס למה שאני רואים על המסך כתמונה יחידה בזכרון. למעשה, ניתן לגרום לדפדפן להתייחס לאלמנטים שונים כשכבה נפרדת, או במילים אחרות – כמספר תמונות נפרדות. ניתן ליצור שכבה נפרדת לאלמנטים מסויימים ובכך לגרום להם להיות עצמאיים ובלתי תלויים באלמנטים נוספים בעמוד.

חשבו על כך רגע, כאשר אלמנט מסויים נמצא ב position:fixed ואנו מסתכלים על שכבה יחידה המכילה את כל האלמנטים כולל אותו אלמנט ב fixed, על הדפדפן לצייר (באופן תיאורטי) את השכבה היחידה בכל פעם מחדש מכיוון והמיקום של אותו אלמנט נמצא כל פעם במיקום אחר יחסית לשאר האלמנטים בעמוד.

למזלינו, הדפדפן יודע לבצע כבר אופטימיזציה למצבים אלו אך לפעמים הוא צריך מעט עזרה. אז כפי שציינו, ניתן לגרום לכך שפעולת ה Repainting לא תתבצע בכל פעם רק מכיוון והדפדפן מתייחס לכל האלמנטים כתמונה יחידה אלא ניתן לקבוע כי אלמנטים מסויימים יהיו בשכבה נפרדת. פעולה זו נקראית layer promotion.

Layer Promotion

היתרון בגישה זו היא שאלמנטים שנצבעים מחדש, או כאלו שמבצעים תנועה כלשהי על המסך באמצעות CSS transforms, יכולים להיות מנוהלים ללא השפעה על אלמנטים אחרים בעמוד. הרעיון מאד דומה לצורה בה עובדת פוטושופ, כאשר שכבות אינדיבידואליות מנוהלות אחת מעל השנייה בכדי ליצור את התמונה הסופית.

התכונה WILL-CHANGE

הדרך הטובה ביותר ליצור שכבה חדשה עבור אלמנט מסויים היא שימוש בתכונה will-change ב CSS. התכונה will-change מספקת אינדיקציה לדפדפן על שינויים שעלולים להתרחש באלמנט מסויים כך שהדפדפן יבצע מראש סוג של אופטימיזציה לאותו אלמנט לפני שהוא משתנה בפועל על המסך.

תכונה זו תעבוד בכל הדפדפנים המודרנים (בגירסתם האחרונה לפחות) וכאשר תתנו לתכונה זו את הערך transform,  תיווצר שכבה חדשה או layer חדש עבור אותו אלמנט.

.moving-element {
  will-change: transform;
}

אגב, אם אתם מעוניינים בתמיכה בדפדפנים ישנים יותר – תוכלו להשתמש בסוג של hack שקיים כבר שנים והוא שימוש ב translateZ כבדוגמה הבאה:

.moving-element {
  transform: translateZ(0);
}

אך שימו לב למספר נקודות בהקשר לתכונה will-change לפני שאתם רצים להשתמש בה:

  • אין להוסיף את התכונה will-change ליותר מדי אלמנטים. הדפדפן מנסה לבצע אופטימיזציה בעצמו לאלמנטים בעמוד ושימוש מופרז בתכונה זו יכול לגרום לצריכת משאבים רבה ואף לגרום להאטת העמוד.
  • הוספה של התכונה ב CSS גורמת לכך שהדפדפן ישמור את האופטימיזציה בזיכרון הרבה מעבר למה שבאמת נחוץ. עדיף להשתמש ב Javsscript על מנת להוסיף את התכונה בדיוק לפני שהאלמנט משתנה ולהסירה לאחר הסיום.
  • אין להשתמש בתכונה will-change רק מפני שאתם חושבים שיהיו בעיות ביצועים כלשהן. השתמשו בתכונה זו רק כאשר אתם חווים בעיית ביצועים וכמפלט אחרון.

בכל אופן, בואו נראה את התוצאה בסאבי בלוג לאחר שהשתמשתי בתכונה will-change עבור אותם אלמנטים בעייתיים שהזכרנו:

 

כפי שאתם שמים לב, כל אותם ריבועים ירוקים נעלמו מכיוון ואותם אלמנטים קיבלו שכבה חדשה ואינם ״מפריעים״ לאלמנטים אחרים במסך. אני יכול להבטיח לכם כאן ועכשיו כי לעולם לא תחוו בעיות ביצועי גלילה בסאבי בלוג 😉

כיצד להוסיף את התכונה will-change באמצעות JavaScript?

לצורך המאמר הוספתי את התכונה will-change באמצעות CSS בסאבי בלוג. אך כפי שציינתי, עדיף להשתמש בתכונה זו באמצעות Javascript בדיוק לפני שהשינוי מתבצע ולהסירה לאחר השינוי. הנה דוגמה המתארת כיצד לבצע זאת עבור אלמנט מסויים באמצעות Javascript:

var el = document.getElementById('element');

// Set will-change when the element is hovered
el.addEventListener('mouseenter', hintBrowser);
el.addEventListener('animationEnd', removeHint);

function hintBrowser() {
  // The optimizable properties that are going to change
  // in the animation's keyframes block
  this.style.willChange = 'transform, opacity';
}

function removeHint() {
  this.style.willChange = 'auto';
}

מספר טיפים לביצועי Frontend טובים יותר

ישנם מספר דברים שבאפשרותכם לעשות בכדי לשפר את ביצועי הגלילה והאנימציות באתר שלכם. כתוצאה משינויים אלו, ה CPU/GPU לא ייאלץ לעבוד כ״כ קשה וזה אף יתורגם לגולשים מרוצים יותר וצריכת סוללה נמוכה יותר במכשירי מובייל. בוא ניתן מספר טיפים:

  • המנעו משימוש בתמונות רקע להם התכונה background-attachment:fixed. בדפדפנים מסויימים אלו יגרמו לצביעה מחדש במהלך גלילה ולביצועים ירודים.
  • אם אתם משתמשים בסליידרים או אנימציות באתר שלכם, וודאו אתם יוצרים עבורם שכבה נפרדת באמצעות התכונה will:change.
  • אם ישנם אפקטים רבים של CSS3, לדוגמה – הרבה פינות מעוגלות (rounded corners), תכונות כמו linear-gradients למינהן והצללות (shadows), שיקלו להסיר אותן או להפחית את השימוש בהן. אין בעיה להשתמש באלו אך זכרו שבמידה וקיימים במידה מופרזת באתר שלכם – תהיה לכך השפעה על ביצועי ה Frontend.
  • תמיד תמיד השתמשו בגודל התמונה המדוייק שעל הדפדפן להציג ותחסכו ממנו לשנות בעצמו את גודל התמונה על המסך. אם אתם עובדים עם וורדפרס, תנו מבט במדריך שכתבתי המסביר על יצירת גדלים של תמונות באתרים אלו.
  • אמנם לא נגענו בחלק זה, אך במידה ואתם משתמשים באנימציות – נסו להשתמש ב requestAnimationFrame. שימוש במטודה זו יכול לשפר את ביצועי האנימציות ואת ה FPS בצורה דרסטית.

לסיכום

כלי המפתחים של כרום מספק המון דרכים בכדי לנתח ולגלות בעיות ביצועים באתר שלכם, בין אם ביצועי Frontend או ביצועי האתר מבחינת זמן טעינה. האמת שבמדריך זה לא הזכרנו דרכים אלו מעבר לשימוש באפשרות ה Paint Flashing שעוזרת לגלות בעיות ביצועים ברמת גלילה וברמת אנימציות.

יצירת שכבה נפרדת עבור אלמנטים מסויימים הינה פעולה שנכון לבצע אם אתם חווים בעיות ביצועים באנימציות ובגלילה. התכונה will-change מהווה פיתרון מצויין, בטח באתרים מורכבים אז אל תפחדו להשתמש בה בעת הצורך. באותו נשימה אומר כי יש להזהר משימוש בתכונה זו בצורה מופרזת.

ואם בנושא גלילה עסקינן, תנו מבט בפוסט שכתבתי על הוספת אנימציות לאלמנטים בזמן גלילה.

מקווה שלא התבלגנתי יותר מדי, זהו נושא מורכב והאמינו לי שלא פשוט לכתוב על נושאים אלו בעברית. בכל מקרה, אם ישנן הערות או תוספות בראש שלכם, אשמח אם תגיבו ותשתפו אותנו בתגובות.

 

רועי יוסף
רועי יוסף

מפתח אתרים ותבניות וורדפרס. מספק אתרים עם ביצועים גבוהים, מותאמים למנועי חיפוש ובעלי קוד ולידי, סמנטי ונקי. צריכים עזרה? צרו איתי קשר.

  • רמי 21 מרץ 2018, 23:15

    אהבתי!

  • איש 7 אוגוסט 2019, 18:01
    $Comment = 'מדריך מצוין';
    exit($Comment);
  • אבירן 20 מאי 2021, 11:58

    תותח, תודה!

תגובה חדשה

הוסיפו קוד באמצעות הכפתורים מטה. למשל, בכדי להוסיף PHP לחצו על הכפתור PHP והוסיפו את הקוד בתוך השורטקוד. מצאתם שגיאה בפוסט? עדכנו אותנו...