با انیمیشن های اسکرول در CSS شروع کنید

۱. قبل از شروع

انیمیشن‌های اسکرول-محور به شما این امکان را می‌دهند که پخش یک انیمیشن را بر اساس موقعیت اسکرول یک محفظه اسکرول کنترل کنید. این بدان معناست که با اسکرول کردن به بالا یا پایین، انیمیشن به جلو یا عقب حرکت می‌کند. علاوه بر این، با انیمیشن‌های اسکرول-محور می‌توانید یک انیمیشن را بر اساس موقعیت یک عنصر در محفظه اسکرول آن نیز کنترل کنید. این به شما امکان می‌دهد جلوه‌های جالبی مانند تصویر پس‌زمینه پارالاکس، نوارهای پیشرفت اسکرول و تصاویری که هنگام نمایش خود را نشان می‌دهند، ایجاد کنید.

قابلیت جدید کروم ۱۱۵، پشتیبانی از مجموعه‌ای از کلاس‌های جاوا اسکریپت و ویژگی‌های CSS است که به شما امکان می‌دهد به راحتی انیمیشن‌های اسکرول‌محور اعلانی ایجاد کنید. این APIهای جدید در کنار APIهای Web Animations و CSS Animations موجود کار می‌کنند.

این آزمایشگاه کد به شما آموزش می‌دهد که چگونه با استفاده از CSS انیمیشن‌های اسکرول-محور ایجاد کنید. با تکمیل این آزمایشگاه کد، با بسیاری از ویژگی‌های جدید CSS که توسط این ویژگی هیجان‌انگیز معرفی می‌شوند، مانند scroll-timeline ، view-timeline ، animation-timeline و animation-range آشنا می‌شوید.

آنچه یاد خواهید گرفت

  • نحوه ایجاد یک افکت پس زمینه پارالکس با Scroll Timeline در CSS.
  • نحوه ایجاد نوار پیشرفت با جدول زمانی پیمایش در CSS.
  • نحوه ایجاد جلوه نمایش تصویر با استفاده از View Timeline در CSS.
  • نحوه هدف قرار دادن انواع مختلف محدوده‌های یک جدول زمانی نمایش در CSS.

آنچه نیاز دارید

یکی از ترکیب‌های دستگاه زیر:

  • نسخه اخیر کروم (۱۱۵ یا بالاتر) در ChromeOS، macOS یا Windows که گزینه «ویژگی‌های پلتفرم وب آزمایشی» روی آن فعال باشد.
  • درک اولیه از HTML
  • درک اساسی از CSS، به ویژه انیمیشن‌ها در CSS

۲. آماده شوید

هر آنچه برای این پروژه نیاز دارید در مخزن گیت‌هاب موجود است. برای شروع، کد را کپی کرده و آن را در محیط توسعه مورد علاقه خود باز کنید.

  1. یک تب جدید در مرورگر باز کنید و به آدرس https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab بروید.
  2. مخزن را کلون کنید.
  3. کد را در IDE مورد نظر خود باز کنید.
  4. برای نصب وابستگی‌ها npm install اجرا کنید.
  5. دستور npm start اجرا کنید و به آدرس http://localhost:3000/ مراجعه کنید.
  6. روش دیگر، اگر npm را نصب ندارید، فایل src/index.html را در کروم باز کنید.

۳. در مورد جدول زمانی انیمیشن اطلاعات کسب کنید

به طور پیش‌فرض، یک انیمیشن متصل به یک عنصر در جدول زمانی سند اجرا می‌شود. این بدان معناست که وقتی صفحه بارگذاری می‌شود، انیمیشن با گذشت زمان به جلو حرکت می‌کند. این جدول زمانی پیش‌فرض انیمیشن است و تاکنون، تنها جدول زمانی انیمیشنی بود که به آن دسترسی داشتید.

با انیمیشن‌های اسکرول‌محور، به دو نوع جدید از جدول زمانی دسترسی پیدا می‌کنید:

  • جدول زمانی پیشرفت پیمایش
  • مشاهده جدول زمانی پیشرفت

در CSS، این جدول‌های زمانی را می‌توان با استفاده از ویژگی animation-timeline به یک انیمیشن متصل کرد. نگاهی به معنای این جدول‌های زمانی جدید و تفاوت آنها با یکدیگر بیندازید.

جدول زمانی پیشرفت پیمایش

یک جدول زمانی پیشرفت اسکرول، یک جدول زمانی انیمیشن است که به پیشرفت در موقعیت اسکرول یک محفظه اسکرول - که به آن اسکرول پورت یا اسکرولر نیز گفته می‌شود - در امتداد یک محور خاص مرتبط است. این جدول زمانی، موقعیت را در یک محدوده اسکرول به درصد پیشرفت در امتداد یک جدول زمانی تبدیل می‌کند.

موقعیت شروع اسکرول نشان دهنده پیشرفت ۰٪ و موقعیت پایان اسکرول نشان دهنده پیشرفت ۱۰۰٪ است. در تصویرسازی زیر، توجه داشته باشید که با اسکرول کردن به پایین، پیشرفت از ۰٪ تا ۱۰۰٪ افزایش می‌یابد.

مشاهده جدول زمانی پیشرفت

این نوع جدول زمانی به پیشرفت نسبی یک عنصر خاص در یک ظرف پیمایش مرتبط است. درست مانند یک جدول زمانی پیشرفت پیمایش، جابجایی پیمایش یک پیمایشگر ردیابی می‌شود. برخلاف یک جدول زمانی پیشرفت پیمایش، موقعیت نسبی یک موضوع در آن پیمایشگر است که پیشرفت را تعیین می‌کند. این قابل مقایسه با IntersectionObserver است که میزان قابل مشاهده بودن یک عنصر در پیمایشگر را ردیابی می‌کند. اگر عنصر در پیمایشگر قابل مشاهده نباشد، متقاطع نیست. اگر در داخل پیمایشگر قابل مشاهده باشد - حتی برای کوچکترین قسمت - متقاطع است.

یک جدول زمانی پیشرفت نمایش از لحظه‌ای که یک موضوع شروع به تقاطع با پیمایشگر می‌کند، آغاز می‌شود و زمانی که موضوع تقاطع با پیمایشگر را متوقف می‌کند، پایان می‌یابد. در تجسم زیر، توجه داشته باشید که پیشرفت از 0٪ زمانی که موضوع وارد ظرف پیمایش می‌شود، شروع به شمارش می‌کند و تا زمانی که ظرف پیمایش را ترک می‌کند، به 100٪ می‌رسد.

به طور پیش‌فرض، یک انیمیشن که به View Progress Timeline متصل است، به کل محدوده آن متصل می‌شود. این از لحظه ورود سوژه به scrollport شروع می‌شود و با خروج سوژه از scrollport پایان می‌یابد.

همچنین می‌توان با مشخص کردن محدوده‌ای که باید به آن متصل شود، آن را به بخش خاصی از جدول زمانی پیشرفت نمایش (View Progress Timeline) پیوند داد. این می‌تواند، به عنوان مثال، فقط زمانی باشد که سوژه وارد اسکرول می‌شود. در تجسم زیر، پیشرفت از زمانی که سوژه وارد ظرف اسکرول می‌شود، از ۰٪ شروع به شمارش می‌کند، اما از لحظه‌ای که کاملاً متقاطع می‌شود، به ۱۰۰٪ می‌رسد.

محدوده‌های احتمالی View Timeline که می‌توانید هدف قرار دهید عبارتند از cover ، contain ، entry ، exit ، entry-crossing و exit-crossing . این محدوده‌ها بعداً در این آزمایشگاه کد توضیح داده می‌شوند، اما اگر بی‌صبرانه منتظر دانستن هستید، از ابزاری که در https://goo.gle/view-timeline-range-tool قرار دارد استفاده کنید تا ببینید هر محدوده چه چیزی را نشان می‌دهد.

۴. یک افکت پس‌زمینه پارالاکس ایجاد کنید

اولین افکتی که باید به صفحه اضافه کنید، یک افکت پس‌زمینه پارالاکس روی تصویر پس‌زمینه اصلی است. وقتی صفحه را به پایین اسکرول می‌کنید، تصویر پس‌زمینه باید حرکت کند، البته با سرعتی متفاوت. برای این کار، به جدول زمانی پیشرفت اسکرول (Scroll Progress Timeline) نیاز دارید.

برای اجرای این امر، دو مرحله باید طی شود:

  1. یک انیمیشن ایجاد کنید که موقعیت تصویر پس زمینه را تغییر دهد.
  2. انیمیشن را به روند اسکرول سند پیوند دهید.

انیمیشن را ایجاد کنید

  1. برای ایجاد انیمیشن، از یک مجموعه فریم کلیدی معمولی استفاده کنید. در آن، موقعیت پس‌زمینه را از ۰٪ عمودی به ۱۰۰٪ تغییر دهید:

src/styles.css

@keyframes move-background {
  from {
    background-position: 50% 0%;
  }
  to {
    background-position: 50% 100%;
  }
}
  1. حالا این کی‌فریم‌ها را به عنصر بدنه (body) وصل کنید:

src/styles.css

body {
  animation: 1s linear move-background;
}

با این کد، انیمیشن move-background به عنصر body اضافه می‌شود. ویژگی animation-duration آن روی یک ثانیه تنظیم شده است و از یک easing linear استفاده می‌کند.

ساده‌ترین راه برای ایجاد یک جدول زمانی Scroll Progress استفاده از تابع scroll() است. این یک جدول زمانی Scroll Progress ناشناس ایجاد می‌کند که می‌توانید آن را به عنوان مقدار برای ویژگی animation-timeline تنظیم کنید.

scroll() یک آرگومان <scroller> و یک آرگومان <axis> را می‌پذیرد.

مقادیر قابل قبول برای آرگومان <scroller> به شرح زیر است:

  • nearest . از نزدیکترین محفظه اسکرول جد (پیش‌فرض) استفاده می‌کند.
  • root . از نمای سند به عنوان ظرف اسکرول استفاده می‌کند.
  • self . از خود عنصر به عنوان ظرف اسکرول استفاده می‌کند.

مقادیر پذیرفته شده برای آرگومان <axis> به شرح زیر است:

  • block . از معیار پیشرفت در امتداد محور بلوکِ ظرف اسکرول استفاده می‌کند (پیش‌فرض).
  • inline ): از معیار پیشرفت در امتداد محور درون‌خطیِ نگهدارنده‌ی اسکرول استفاده می‌کند.
  • y . از معیار پیشرفت در امتداد محور y ظرف اسکرول استفاده می‌کند.
  • x . از معیار پیشرفت در امتداد محور x ظرف اسکرول استفاده می‌کند.

برای پیوند دادن انیمیشن به اسکرول کننده ریشه در محور بلوک، مقادیری که باید به تابع scroll() ارسال شوند، root و block هستند. در مجموع، مقدار scroll(root block) می‌شود.

  • scroll(root block) به عنوان مقدار برای ویژگی animation-timeline در بدنه تنظیم کنید.
  • علاوه بر این، از آنجایی که animation-duration بیان شده بر حسب ثانیه بی‌معنی است، مدت زمان را روی auto تنظیم کنید. اگر animation-duration مشخص نکنید، به طور پیش‌فرض روی auto تنظیم می‌شود.

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(root block);
}

از آنجایی که اسکرول کننده ریشه، نزدیکترین اسکرول کننده والد برای عنصر body نیز هست، می‌توانید از مقدار nearest نیز استفاده کنید:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(nearest block);
}

از آنجا که nearest و block مقادیر پیش‌فرض هستند، حتی می‌توانید آنها را حذف کنید. در این صورت، کد را می‌توان به این صورت ساده کرد:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll();
}

تغییرات خود را تأیید کنید

اگر همه چیز خوب پیش رفته باشد، اکنون باید این را داشته باشید:

اگر اینطور نیست، شاخه solution-step-1 کد را بررسی کنید.

۵. یک نوار پیشرفت برای گالری تصاویر ایجاد کنید

در صفحه یک چرخ فلک افقی وجود دارد که به یک نوار پیشرفت نیاز دارد تا نشان دهد در حال حاضر کدام عکس را مشاهده می‌کنید.

نشانه‌گذاری برای چرخ و فلک به این شکل است:

src/index.html

<div class="gallery">
  <div class="gallery__scrollcontainer" style="--num-images: 3;">
    <div class="gallery__progress"></div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
  </div>
</div>

فریم‌های کلیدی برای نوار پیشرفت از قبل در جای خود قرار گرفته‌اند و به این شکل هستند:

src/styles.css

@keyframes adjust-progress {
  from {
    transform: scaleX(calc(1 / var(--num-images)));
  }
  to {
    transform: scaleX(1);
  }
}

این انیمیشن باید به عنصر gallery__progress با یک جدول زمانی پیشرفت اسکرول (Scroll Progress Timeline) متصل شود. همانطور که در مرحله قبل نشان داده شد، می‌توانید با ایجاد یک جدول زمانی پیشرفت اسکرول ناشناس با تابع scroll() به این هدف دست یابید:

src/styles.css

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  animation-timeline: scroll(nearest inline);
}

اگرچه ممکن است به نظر برسد که این قطعه کد کار می‌کند، اما به دلیل نحوه جستجوی خودکار کانتینر اسکرول با استفاده از nearest work، اینطور نیست. هنگام جستجوی نزدیکترین اسکرول، عنصر فقط عناصری را در نظر می‌گیرد که می‌توانند بر موقعیت آن تأثیر بگذارند. از آنجا که .gallery__progress به صورت absolute موقعیت‌یابی شده است، اولین عنصر والدی که موقعیت آن را تعیین می‌کند، عنصر .gallery است زیرا position: relative روی آن اعمال شده است. این بدان معناست که عنصر .gallery__scrollcontainer - که همان اسکرولری است که باید هدف‌گیری شود - در طول این جستجوی خودکار اصلاً در نظر گرفته نمی‌شود.

برای حل این مشکل، یک جدول زمانی با نام Scroll Progress در عنصر .gallery__scrollcontainer ایجاد کنید و .gallery__progress را با استفاده از آن نام به آن پیوند دهید.

برای ایجاد یک جدول زمانی پیشرفت پیمایش نامگذاری شده روی یک عنصر، ویژگی CSS scroll-timeline-name را در کانتینر پیمایش روی مقداری به دلخواه خود تنظیم کنید. مقدار باید با -- شروع شود.

از آنجا که گالری به صورت افقی اسکرول می‌شود، باید ویژگی scroll-timeline-axis را نیز تنظیم کنید. مقادیر مجاز همان آرگومان <axis> در تابع scroll() هستند.

در نهایت، برای پیوند دادن انیمیشن به جدول زمانی پیشرفت اسکرول، ویژگی animation-timeline را روی عنصری که باید متحرک شود، برابر با مقدار شناسه مورد استفاده برای scroll-timeline-name تنظیم کنید.

  • فایل styles.css را تغییر دهید تا موارد زیر را شامل شود:

src/styles.css

.gallery__scrollcontainer {
  /* Create the gallery-is-scrolling timeline */
  scroll-timeline-name: --gallery-is-scrolling;
  scroll-timeline-axis: inline;
}

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  /* Set gallery-is-scrolling as the timeline */
  animation-timeline: --gallery-is-scrolling;
}

تغییرات خود را تأیید کنید

اگر همه چیز خوب پیش رفته باشد، اکنون باید این را داشته باشید:

اگر اینطور نیست، شاخه solution-step-2 کد را بررسی کنید.

۶. تصاویر گالری را هنگام ورود و خروج از اسکرول پورت متحرک کنید

یک جدول زمانی پیشرفت مشاهده ناشناس تنظیم کنید

یک افکت خوب برای اضافه کردن، محو شدن تصاویر گالری هنگام نمایش است. برای این کار، می‌توانید از View Progress Timeline استفاده کنید.

برای ایجاد یک جدول زمانی پیشرفت نمایش، می‌توانید از تابع view() استفاده کنید. آرگومان‌های پذیرفته شده آن عبارتند از <axis> و <view-timeline-inset> .

  • <axis> همان چیزی است که در جدول زمانی پیشرفت اسکرول وجود دارد و مشخص می‌کند کدام محور باید ردیابی شود.
  • با استفاده از <view-timeline-inset> می‌توانید یک فاصله (مثبت یا منفی) برای تنظیم مرزها، زمانی که یک عنصر در دید در نظر گرفته می‌شود یا خیر، تعیین کنید.
  • فریم‌های کلیدی از قبل در جای خود قرار دارند، بنابراین فقط باید آنها را پیوست کنید. برای انجام این کار، یک جدول زمانی مشاهده پیشرفت در هر عنصر .gallery__entry ایجاد کنید.

src/styles.css

@keyframes animate-in {
  from {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  to {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
}

محدود کردن محدوده‌ی نمایش جدول زمانی پیشرفت

اگر CSS را ذخیره کنید و صفحه را بارگذاری کنید، می‌بینید که عناصر کم‌رنگ می‌شوند، اما به نظر می‌رسد چیزی غیرعادی است. وقتی کاملاً از دید خارج می‌شوند، شفافیت آنها از 0 شروع می‌شود و وقتی کاملاً از دید خارج می‌شوند، شفافیت آنها به 1 می‌رسد.

دلیلش این است که محدوده پیش‌فرض برای View Progress Timeline، محدوده کامل است. این محدوده به عنوان محدوده cover شناخته می‌شود.

  1. برای اینکه فقط محدوده entry موضوع را هدف قرار دهید، از ویژگی animation-range در CSS استفاده کنید تا زمان اجرای انیمیشن را محدود کنید.

src/styles.css

.gallery__entry {
  animation: linear fade-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry 0% entry 100%;
}

اکنون انیمیشن از entry 0% (فاعل در شرف ورود به پیمایشگر است) تا entry 100% (فاعل به طور کامل وارد پیمایشگر شده است) اجرا می‌شود.

محدوده‌های ممکن برای نمایش جدول زمانی به شرح زیر است:

  • cover . نشان دهنده طیف کامل جدول زمانی پیشرفت نمایش است.
  • entry . نشان‌دهنده‌ی بازه زمانی است که کادر اصلی وارد محدوده‌ی دید پیشرفت نما می‌شود.
  • exit . نشان‌دهنده‌ی بازه زمانی است که کادر اصلی از محدوده‌ی دید پیشرفت نما خارج می‌شود.
  • entry-crossing . نشان‌دهنده محدوده‌ای است که در طی آن کادر اصلی از لبه مرزی انتهایی عبور می‌کند.
  • exit-crossing . نشان‌دهنده‌ی بازه زمانی است که کادر اصلی از لبه‌ی مرزی شروع عبور می‌کند.
  • contain . نشان‌دهنده‌ی بازه زمانی است که کادر اصلی یا به‌طور کامل توسط آن احاطه شده است یا به‌طور کامل، بازه دید پیشرفت نمای خود را در داخل اسکرول‌پورت پوشش می‌دهد. این بستگی به این دارد که سوژه از اسکرول‌ور بلندتر یا کوتاه‌تر باشد.

از ابزاری که در آدرس https://goo.gle/view-timeline-range-tool قرار دارد استفاده کنید تا ببینید هر محدوده چه چیزی را نشان می‌دهد و درصدها چگونه بر موقعیت‌های شروع و پایان تأثیر می‌گذارند.

  1. از آنجا که محدوده‌های شروع و پایان در اینجا یکسان هستند و از آفست‌های پیش‌فرض استفاده می‌شود، animation-range به یک نام محدوده انیمیشن واحد ساده کنید:

src/styles.css

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry;
}
  • برای محو کردن تصاویر هنگام خروج از اسکرول، می‌توانید همان کار انیمیشن متحرک‌سازی را انجام دهید، اما محدوده‌ی متفاوتی را هدف قرار دهید.

src/styles.css

@keyframes animate-out {
  from {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  to {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in, linear animate-out;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry, exit;
}

فریم‌های کلیدی animate-in به محدوده entry و فریم‌های کلیدی animate-out به محدوده exit اعمال می‌شوند.

تغییرات خود را تأیید کنید

اگر همه چیز خوب پیش رفته باشد، اکنون باید این را داشته باشید:

اگر اینطور نیست، شاخه solution-step-3 کد را بررسی کنید.

۷. تصاویر گالری را هنگام ورود و خروج از اسکرول‌پورت، با استفاده از یک مجموعه فریم کلیدی، متحرک‌سازی کنید.

مورد مربوط به یک مجموعه از فریم‌های کلیدی

به جای اتصال دو انیمیشن به محدوده‌های مختلف، می‌توان یک مجموعه از فریم‌های کلیدی ایجاد کرد که از قبل حاوی اطلاعات محدوده باشد.

شکل فریم‌های کلیدی به این شکل است:

@keyframes keyframes-name {
  range-name range-offset {
    ...
  }
  range-name range-offset {
    ...
  }
}
  1. فریم‌های کلیدی محو شدن و محو شدن را مانند این ترکیب کنید:

src/styles.css

@keyframes animate-in-and-out {
  entry 0% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  entry 90% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }

  exit 10% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  exit 100% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}
  1. وقتی اطلاعات محدوده در فریم‌های کلیدی وجود داشته باشد، دیگر نیازی به مشخص کردن جداگانه animation-range ندارید. فریم‌های کلیدی را به عنوان ویژگی animation پیوست کنید.

src/styles.css

.gallery__entry {
  animation: linear animate-in-and-out both;
  animation-duration: auto;
  animation-timeline: view(inline);
}

تغییرات خود را تأیید کنید

اگر همه چیز خوب پیش رفته باشد، باید همان نتیجه مرحله قبل را داشته باشید. در غیر این صورت، شاخه solution-step-4 کد را بررسی کنید.

۸. تبریک می‌گویم!

شما این آزمایشگاه کدنویسی را به پایان رساندید و اکنون می‌دانید که چگونه جدول زمانی پیشرفت پیمایش و جدول زمانی پیشرفت مشاهده را در CSS ایجاد کنید!

اطلاعات بیشتر

منابع: