Memulai animasi berbasis scroll dalam CSS

1. Sebelum memulai

Animasi berbasis scroll dapat Anda gunakan untuk mengontrol pemutaran animasi berdasarkan posisi scroll dalam container scroll. Artinya, saat Anda melakukan scroll ke atas atau ke bawah, animasi akan bergerak maju atau mundur. Selain itu, dengan animasi berbasis scroll, Anda juga dapat mengontrol animasi berdasarkan posisi elemen dalam container scroll-nya. Dengan demikian Anda dapat membuat efek menarik seperti gambar latar paralaks, status progres scroll, dan gambar yang muncul di tampilan.

Hal baru dalam Chrome 114 adalah dukungan untuk set class JavaScript dan properti CSS, sehingga Anda dapat dengan mudah membuat animasi berbasis scroll yang deklaratif. API baru ini berfungsi bersama dengan Web Animations API dan CSS Animations API yang sudah ada.

Codelab ini berisi informasi mengenai cara membuat animasi berbasis scroll menggunakan CSS. Dengan menyelesaikan codelab ini, Anda akan memahami banyak properti CSS baru yang diperkenalkan oleh fitur menarik ini, seperti scroll-timeline, view-timeline, animation-timeline, dan animation-range.

Yang akan Anda pelajari

  • Cara membuat efek latar belakang paralaks dengan Linimasa Scroll di CSS.
  • Cara membuat status progres dengan Linimasa Scroll di CSS.
  • Cara membuat efek reveal gambar dengan Linimasa Tampilan di CSS.
  • Cara menargetkan berbagai jenis rentang Linimasa Tampilan di CSS.

Yang Anda butuhkan

Salah satu dari kombinasi perangkat berikut:

  • Chrome versi terbaru (114 atau yang lebih baru) di ChromeOS, macOS, atau Windows
  • Pemahaman dasar tentang HTML
  • Pemahaman dasar tentang CSS, terutama animasi di CSS

2. Memulai persiapan

Semua yang Anda perlukan untuk project ini tersedia di repositori GitHub. Untuk memulai, clone kode dan buka di lingkungan pengembangan favorit Anda.

  1. Buka tab browser baru lalu masuk ke https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab.
  2. Buat cloning repositori:
  3. Buka kode dalam IDE pilihan Anda.
  4. Jalankan npm install untuk menginstal dependensi.
  5. Jalankan npm start dan buka http://localhost:3000/.
  6. Atau jika npm Anda belum terinstal, buka file src/index.html di Chrome.

3. Mempelajari linimasa animasi

Secara default, animasi yang terkait dengan suatu elemen berjalan di Linimasa Dokumen. Itu berarti saat halaman dimuat, tick animasi akan bergerak maju seiring waktu. Ini adalah linimasa animasi default, dan sampai sekarang, merupakan satu-satunya linimasa animasi yang dapat Anda akses.

Dengan animasi berbasis scroll, Anda dapat mengakses dua jenis linimasa yang baru:

  • Linimasa Progres Scroll
  • Linimasa Progres Tampilan

Dalam CSS, linimasa ini dapat terkait dengan animasi yang menggunakan properti animation-timeline. Pelajari makna linimasa baru ini dan perbedaannya satu sama lain.

Linimasa Progres Scroll

Linimasa Progres Scroll adalah linimasa animasi yang dikaitkan dengan progres pada posisi scroll dalam container scroll yang juga disebut sebagai area scroll atau scroller di sepanjang sumbu tertentu. Linimasa ini mengonversi posisi dalam rentang scroll menjadi persentase progres di sepanjang linimasa.

Posisi scroll awal menggambarkan progres 0% dan posisi scroll akhir menggambarkan progres 100%. Dalam visualisasi berikut, perhatikan bahwa progres terus meningkat dari 0% ke 100% saat Anda menggerakkan scroller ke bawah.

Linimasa Progres Tampilan

Jenis linimasa ini dikaitkan dengan progres relatif dalam elemen tertentu di dalam container scroll. Seperti halnya Linimasa Progres Scroll, offset scroll di scroller akan dilacak. Berbeda dengan Linimasa Progres Scroll, posisi subjek yang relatif dalam scroller tertentu adalah yang menentukan progresnya. Ini sebanding dengan IntersectionObserver, yang melacak seberapa besar suatu elemen terlihat dalam scroller. Jika tidak terlihat dalam scroller, berarti elemen tersebut tidak berpotongan. Jika terlihat dalam scroller, sekalipun untuk bagian terkecil, berarti elemen tersebut berpotongan.

Linimasa Progres Tampilan dimulai sejak subjek mulai berpotongan dengan scroller dan berakhir saat subjek berhenti berpotongan dengan scroller. Dalam visualisasi berikut, perhatikan bahwa progres mulai dihitung naik dari 0% saat subjek masuk ke container scroll dan mencapai 100% saat subjek keluar dari container scroll.

Secara default, animasi yang dikaitkan dengan Linimasa Progres Tampilan terhubung ke seluruh rentangnya. Ini dimulai sejak subjek masuk ke area scroll dan selesai saat subjek keluar dari area scroll.

Anda juga dapat mengaitkannya ke bagian tertentu dalam Linimasa Progres Tampilan dengan menentukan rentang yang seharusnya dikaitkan. Ini dapat terjadi, misalnya, hanya saat subjek masuk ke scroller. Dalam visualisasi berikut, progres mulai dihitung naik dari 0% saat subjek masuk ke container scroll, tetapi sudah mencapai 100% sejak subjek sepenuhnya berpotongan.

Rentang Linimasa Tampilan yang mungkin dapat Anda targetkan adalah cover, contain, entry, exit, entry-crossing, dan exit-crossing. Rentang-rentang ini akan dijelaskan nanti dalam codelab ini, tetapi jika Anda sudah tidak sabar untuk menunggu, gunakan alat yang ada di https://goo.gle/view-timeline-range-tool untuk mengetahui arti dari setiap rentang.

4. Membuat efek latar belakang paralaks

Efek pertama untuk ditambahkan ke halaman adalah efek latar belakang paralaks di gambar latar utama. Saat Anda men-scroll ke bawah halaman, gambar latar seharusnya bergerak, meskipun kecepatannya berbeda. Untuk tujuan ini, Anda mengandalkan Linimasa Progres Scroll

Untuk menerapkannya, ada dua langkah yang harus dilakukan:

  1. Membuat animasi yang memindahkan posisi gambar latar.
  2. Menautkan animasi ke progres scroll dokumen.

Membuat animasi

  1. Untuk membuat animasi, gunakan set keyframe yang reguler. Di dalamnya, gerakkan posisi latar dari 0% secara vertikal ke 100%:

src/styles.css

@keyframes move-background {
  from {
    background-position: 50% 0%;
  }
  to {
    background-position: 50% 100%;
  }
}
  1. Sekarang, kaitkan keyframe ini ke elemen isi:

src/styles.css

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

Dengan kode ini, animasi move-background ditambahkan ke elemen isi. Properti animation-duration disetel ke satu detik, dan ini menggunakan easing linear.

Cara termudah untuk membuat Linimasa Progres Scroll adalah menggunakan fungsi scroll(). Linimasa Progres Scroll anonim yang dibuat dapat Anda tetapkan sebagai nilai untuk properti animation-timeline.

Fungsi scroll() menerima <scroller> dan argumen <axis>.

Nilai yang diterima untuk argumen <scroller> adalah sebagai berikut:

  • nearest. Menggunakan container scroll ancestor paling dekat (default).
  • root. Menggunakan area pandang dokumen sebagai container scroll
  • self. Menggunakan elemen itu sendiri sebagai container scroll.

Nilai yang diterima untuk argumen <axis> adalah sebagai berikut:

  • block. Menggunakan pengukuran progres di sepanjang sumbu blok dalam container scroll (default).
  • inline. Menggunakan pengukuran progres di sepanjang sumbu yang sejajar dalam container scroll.
  • y. Menggunakan pengukuran progres di sepanjang sumbu y dalam container scroll.
  • x. Menggunakan pengukuran progres di sepanjang sumbu x dalam container scroll.

Untuk menautkan animasi ke scroller root di sumbu blok, nilai yang akan diteruskan ke scroll() adalah root dan block: scroll(root block).

  • Tetapkan scroll(root block) sebagai nilai untuk properti animation-timeline di elemen isi. Selain itu, karena animation-duration yang dinyatakan dalam detik tidak mungkin diterapkan, tetapkan durasi ke auto. Jika Anda tidak menentukan animation-duration, nilainya akan dibuat default ke auto.

src/styles.css

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

Karena scroller root juga kebetulan merupakan scroller induk paling dekat untuk elemen isi, Anda juga dapat menggunakan nilai nearest:

src/styles.css

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

Karena nearest dan block merupakan nilai default, Anda bahkan dapat memilih untuk mengabaikannya. Dalam hal ini, kode dapat disederhanakan menjadi:

src/styles.css

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

Memverifikasi perubahan Anda

Jika semua berjalan lancar, Anda seharusnya sudah memiliki ini:

Jika tidak, periksa cabang solution-step-1 dari kode.

5. Membuat status progres untuk galeri gambar

Di halaman terdapat carousel horizontal yang membutuhkan status progres untuk menunjukkan foto yang saat ini Anda lihat.

Markup untuk carousel akan terlihat seperti ini:

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>

Keyframe untuk status progres sudah diterapkan dan terlihat seperti ini:

src/styles.css

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

Animasi ini perlu dikaitkan dengan elemen .gallery__progress dengan Linimasa Progres Scroll. Seperti yang dijelaskan di tahap sebelumnya, Anda dapat mencapai tahap ini dengan membuat Linimasa Progres Scroll anonim dengan fungsi scroll():

src/styles.css

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

Cara alternatif untuk menetapkan Linimasa Progres Scroll adalah menggunakan Linimasa yang bernama. Cara ini sedikit lebih panjang, tetapi bisa jadi berguna saat Anda tidak menargetkan scroller induk atau scroller root, atau saat halaman menggunakan beberapa linimasa. Dengan cara ini, Anda dapat mengidentifikasi Linimasa Progres Scroll berdasarkan nama yang Anda berikan.

Untuk membuat Linimasa Progres Scroll bernama pada suatu elemen, tetapkan nilai properti CSS scroll-timeline-name dalam container scroll sesuai keinginan Anda.

Karena galeri di-scroll secara horizontal, Anda juga perlu menetapkan properti scroll-timeline-axis. Nilai yang diizinkan sama dengan argumen <axis> dari scroll().

Terakhir, untuk menautkan animasi ke Linimasa Progres Scroll, tetapkan properti animation-timeline di elemen yang perlu dianimasikan ke nilai sama seperti yang digunakan ID untuk scroll-timeline-name.

  • Ubah file styles.css agar mencakup hal berikut:

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;
}

Memverifikasi perubahan Anda

Jika semua berjalan lancar, Anda seharusnya sudah memiliki ini:

Jika tidak, periksa cabang solution-step-2 dari kode.

6. Menganimasikan gambar galeri saat masuk dan keluar dari area scroll

Menyiapkan Linimasa Progres Tampilan anonim

Efek menarik untuk ditambahkan adalah memperjelas gambar galeri saat muncul di tampilan. Untuk melakukannya, Anda dapat menggunakan Linimasa Progres Tampilan.

Untuk membuat Linimasa Progres Tampilan, Anda dapat menggunakan fungsi view(). Argumen yang diterima adalah <axis> dan <view-timeline-inset>.

  • <axis> adalah sama dengan dari Linimasa Progres Scroll serta menentukan sumbu yang akan dilacak.
  • Dengan <view-timeline-inset>, Anda dapat menentukan offset (positif atau negatif) untuk menyesuaikan batas saat elemen dianggap akan terlihat atau tidak.
  • Keyframe sudah diterapkan sehingga Anda hanya perlu mengaitkannya. Untuk melakukannya, buat Linimasa Progres Tampilan di tiap elemen .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);
}

Membatasi rentang Linimasa Progres Tampilan

Jika Anda menyimpan CSS dan memuat halaman, Anda akan melihat elemen terlihat jelas, tetapi ada yang tampaknya salah. Elemen dimulai pada opasitas 0 saat sepenuhnya berada di luar pandangan dan hanya berakhir pada opasitas 1 saat elemen sepenuhnya keluar.

Hal itu terjadi karena rentang default untuk Linimasa Progres Tampilan adalah rentang penuh. Ini disebut sebagai rentang cover.

  1. Untuk menargetkan hanya rentang entry pada subjek, gunakan properti CSS animation-range untuk membatasi kapan animasi seharusnya berjalan.

src/styles.css

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

Animasi kini berjalan dari entry 0% (subjek akan memasuki scroller) ke entry 100% (subjek telah keluar dari scroller sepenuhnya).

Rentang Linimasa Tampilan yang mungkin adalah sebagai berikut:

  • cover. Menggambarkan rentang penuh dari linimasa progres tampilan.
  • entry. Menggambarkan rentang selama kotak utama memasuki rentang visibilitas progres tampilan.
  • exit. Menggambarkan rentang selama kotak utama keluar dari rentang visibilitas progres tampilan.
  • entry-crossing. Menggambarkan rentang selama kotak utama bersilangan dengan tepi batas akhir.
  • exit-crossing. Menggambarkan rentang selama kotak utama bersilangan dengan tepi batas awal.
  • contain. Menggambarkan rentang selama kotak utama sepenuhnya tertampung atau sepenuhnya tercakup oleh rentang visibilitas progres tampilannya dalam area scroll. Hal ini bergantung pada apakah subjek lebih tinggi atau lebih pendek daripada scroller.

Gunakan alat yang ada di https://goo.gle/view-timeline-range-tool untuk mengetahui arti dari tiap rentang dan bagaimana persentase memengaruhi posisi awal dan akhir.

  1. Karena rentang awal dan akhir sama di sini serta offset default digunakan, sederhanakan animation-range menjadi nama rentang animasi tunggal:

src/styles.css

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry;
}
  • Untuk memburamkan gambar saat keluar dari scroller, Anda dapat melakukan cara yang sama seperti animasi animate-in, tetapi menargetkan rentang yang berbeda.

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;
}

Keyframe animate-in akan diterapkan ke rentang entry, sedangkan keyframe animate-out akan diterapkan ke rentang exit.

Memverifikasi perubahan Anda

Jika semua berjalan lancar, Anda seharusnya sudah memiliki ini:

Jika tidak, periksa cabang solution-step-3 dari kode.

7. Menganimasikan gambar galeri saat masuk dan keluar dari area scroll, menggunakan satu set keyframe

Kasus untuk satu set keyframe

Alih-alih mengaitkan dua animasi ke rentang yang berbeda, buat satu set keyframe yang sudah berisi informasi rentang.

Bentuk keyframe akan terlihat seperti ini:

@keyframes keyframes-name {
  range-name range-offset {
    ...
  }
  range-name range-offset {
    ...
  }
}
  1. Gabungkan keyframe fade-in dan fade-out seperti ini:

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. Saat informasi rentang ada dalam keyframe, Anda tidak perlu lagi menentukan animation-range secara terpisah. Kaitkan keyframe sebagai properti animation.

src/styles.css

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

Memverifikasi perubahan Anda

Jika semua berjalan lancar, Anda semestinya akan mendapatkan hasil yang sama seperti pada langkah sebelumnya. Jika tidak, periksa cabang solution-step-4 dari kode.

8. Selamat!

Anda sudah menyelesaikan codelab ini dan kini mengetahui cara membuat Linimasa Progres Scroll dan Linimasa Progres Tampilan di CSS.

Pelajari Lebih Lanjut

Referensi: