אנימציות שמונפשות בעת הגלילה – ScrollReveal למפתחים

אנימציות היא אחת הדרכים הכי טובות לדאוג לאתר סטטי לקום לחיים.

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

איך נגדיר מה יקרה? יש כל מני כלים לזה, פה ניעזר ב־ScrollReveal.

צילום מסך מתוך האתר הרשמי של ScrollReveal

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

יש לו דוקומנטציה מאוד נוחה והוא תומך בדפדפנים מרובים.

Browser compatibility matrix
הדפדפנים שבו ScrollReveal תומך – מתוך דף הGitHub

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


בעיות נקודתיות ו־Code Snippets שעוזרים

מה עושים כשרוצים להנפיש כמה אלמנטים בבת אחת, בלי קשר ל־Scroll Position שלהם?

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

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

הדרך היחידה לפתור את זה היא להנפיש בעזרת CSS את האלמנטים של Div־האב שעוטף את כל האלמנטים שנרצה להנפיש, וכשהמשתמש גולל וDiv־האב מתגלה בScroll Position, מוסיפים לו Class של is-visible, כך ההנפשה של כל הילדים שלו יפעלו בוות אחת.

אז דבר ראשון שצריך לעשות זה לדאוג שאלמנט האב אשר יכיל את Class המצבים (is-visible, is-animating וכו') יהיה נטול אפקטים, כדי שקלאס is-visible יוצג באופן מיידי, בלי שהייה.

הקוד הבא דואג לזה:


  function afterReset(el) {
    el.classList.remove('is-animating');
  }
  function afterReveal(el) {
    el.classList.remove('is-animating');
    el.classList.add('is-visible');
  }
  function beforeReset(el) {
    el.classList.remove('is-visible');
    el.classList.add('is-animating');
  }
  function beforeReveal(el) {
    el.classList.add('is-animating');
  }

  ScrollReveal().reveal('.proccess-content', {
    // Options
    // reset: true,
    viewFactor: 0.7,

    // No Effects
    delay:    0,
    distance: 0,
    duration: 0,
    scale:    1,
    opacity:  null,
    rotate:   { x: 0, y: 0, z: 0, },
    cleanup: true,

    // Add/Remove Class States
    afterReset: afterReset,
    afterReveal: afterReveal,
    beforeReset: beforeReset,
    beforeReveal: beforeReveal
  });

והדבר השני שנצטרך לעשות זה להנפיש את הילדים שלנו ב־CSS, כאשר אלמנט האב שלנו div.parent-element מכיל Class של .is-visible.

הנה קוד SCSS שכתבתי, שאחראי לאנימציה שמיד תראו:

div.parent-element {
    &.is-visible {
        span.counter .number {
            transform: translateY(0em) scale(1) rotate(0deg);
            opacity: 1;
        }
        .words span.word {
            $duration: 1000ms;
            $initial_wait: 500ms;
            $delay_between_each: 80ms;
            transform: translateY(0em) scale(1);
            opacity: 1;
            @for $i from 0 through 10 {
                &:nth-child(#{$i}) {
                transition-delay: $initial_wait + $delay_between_each * $i;
                animation-delay: $initial_wait + $delay_between_each * $i;
                }
            }
        }
    }
}

וכך נראה הקוד הזה בפעולה:

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

יש גם ScrollReveal שנועד ל Angular-CLI?

כמובן, יש את התוסף הרשמי של ScrollReveal לאנגולר – ngx-scrollreveal. ההדרכה הבסיסית על ההתקנה והכל נמצאת שם, והוא מאוד נוח לשימוש. אפשר להפעיל את ה־ScrollReveal בתור Directive על האלמנט עצמו, כך שמאוד קל לכתוב אנימציות כאלה.

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

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

דבר ראשון צריך לדאוג להכין script.js שנייבא דרך angular.json. בקובץ הזה נשים את הקוד שרשום למעלה, ונתחום אותו בפונקציה גלובלית שנפעיל מאוחר יותר ב־Component הרלוונטי.

הנה הקוד כאשר הוא כבר תחום בפונקציה גלובלית runScrollReveal() שהכנסתי לקובץ script.js:

function runScrollReveal() {
  function afterReset(el) {
    el.classList.remove('is-animating');
  }
  function afterReveal(el) {
    el.classList.remove('is-animating');
    el.classList.add('is-visible');
  }
  function beforeReset(el) {
    el.classList.remove('is-visible');
    el.classList.add('is-animating');
  }
  function beforeReveal(el) {
    el.classList.add('is-animating');
  }

  ScrollReveal().reveal('.proccess-content', {
    // Options
    // reset: true,
    viewFactor: 0.7,

    // No Effects
    delay:    0,
    distance: 0,
    duration: 0,
    scale:    1,
    opacity:  null,
    rotate:   { x: 0, y: 0, z: 0, },
    cleanup: true,

    // Add/Remove Class States
    afterReset: afterReset,
    afterReveal: afterReveal,
    beforeReset: beforeReset,
    beforeReveal: beforeReveal
  });
}

עכשיו, כשה־Component שלנו יוצג (נדע זאת בעזרת NgOnOnit), נפעיל את הפונקציה הגלובלית:

  ngOnInit() {
    runScrollReveal();
  }

כעת ייתכן ש־TsLint יזהיר אותנו שהפונקציה runScrollReveal() לא קיימת – הגיוני, כי לא הגדרנו אותה בקוד באופן שה Linter מבין, למרות שהיא כן תהיה שם אחרי שנפעיל את האפליקציה בעזרת ng serve או ng build.

כדי להסתיר את האזהרה ב־Component שלנו, צריך לשים את השורה הבאה אחרי כל ה־Imports:

declare function runScrollReveal(): any; 

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

דברים שאני כותב, קוד ופיתוח אתרים, , , ,

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

פוסט בהפתעה?