ทำให้องค์ประกอบเคลื่อนไหวขณะเลื่อนด้วยภาพเคลื่อนไหวที่ขับเคลื่อนด้วยการเลื่อน

ดูวิธีใช้ไทม์ไลน์การเลื่อนและไทม์ไลน์มุมมองเพื่อสร้างภาพเคลื่อนไหวที่ทำงานตามการเลื่อนในลักษณะที่ประกาศ

เผยแพร่: 5 พฤษภาคม 2023

ภาพเคลื่อนไหวที่ทำงานตามการเลื่อน

การรองรับเบราว์เซอร์

  • Chrome: 115
  • Edge: 115
  • Firefox: อยู่หลังธง
  • Safari: ไม่รองรับ

แหล่งที่มา

ภาพเคลื่อนไหวที่ทำงานตามการเลื่อนเป็นรูปแบบ UX ทั่วไปบนเว็บ ภาพเคลื่อนไหวที่ทำงานตามการเลื่อนจะเชื่อมโยงกับตำแหน่งการเลื่อนของคอนเทนเนอร์การเลื่อน ซึ่งหมายความว่าเมื่อคุณเลื่อนขึ้นหรือลง ภาพเคลื่อนไหวที่ลิงก์จะกรอไปข้างหน้าหรือย้อนกลับโดยตอบสนองโดยตรง ตัวอย่างของเอฟเฟกต์ดังกล่าว ได้แก่ พื้นหลังแบบพารัลแลกซ์หรือตัวบ่งชี้การอ่านที่เคลื่อนไหวขณะที่คุณเลื่อน

ตัวบ่งชี้การอ่านที่ด้านบนของเอกสาร ซึ่งเลื่อนตามการเลื่อน

ภาพเคลื่อนไหวที่ทำงานตามการเลื่อนประเภทหนึ่งคือภาพเคลื่อนไหวที่เชื่อมโยงกับตําแหน่งขององค์ประกอบภายในคอนเทนเนอร์การเลื่อน เช่น องค์ประกอบจะค่อยๆ ปรากฏขึ้นเมื่อเข้ามาอยู่ในมุมมอง

รูปภาพในหน้านี้จะค่อยๆ ปรากฏขึ้นเมื่อเข้ามาอยู่ในมุมมอง

วิธีคลาสสิกในการสร้างเอฟเฟกต์ประเภทนี้คือตอบสนองต่อเหตุการณ์การเลื่อนในเธรดหลัก ซึ่งจะทำให้เกิดปัญหาหลัก 2 ข้อดังนี้

  • เบราว์เซอร์สมัยใหม่จะเลื่อนในกระบวนการแยกต่างหาก จึงส่งเหตุการณ์การเลื่อนแบบไม่พร้อมกัน
  • ภาพเคลื่อนไหวในเธรดหลักอาจกระตุก

ซึ่งทำให้การสร้างภาพเคลื่อนไหวที่ทำงานตามการเลื่อนที่มีประสิทธิภาพและซิงค์กับการเลื่อนเป็นไปไม่ได้หรือทำได้ยากมาก

ตั้งแต่ Chrome เวอร์ชัน 115 เป็นต้นไป จะมีชุด API และแนวคิดใหม่ที่คุณสามารถใช้เพื่อเปิดใช้ภาพเคลื่อนไหวที่ทำงานตามการเลื่อนแบบประกาศได้ ซึ่งได้แก่ Scroll Timelines และ View Timelines

แนวคิดใหม่เหล่านี้ผสานรวมกับ Web Animations API (WAAPI) และ CSS Animations API ที่มีอยู่ ซึ่งช่วยให้รับประโยชน์จาก API ที่มีอยู่เหล่านี้ได้ ซึ่งรวมถึงความสามารถในการแสดงภาพเคลื่อนไหวที่ทำงานตามการเลื่อนออกจากเธรดหลัก ใช่ คุณอ่านไม่ผิด ตอนนี้คุณสามารถสร้างภาพเคลื่อนไหวที่ราบรื่นซึ่งทำงานตามการเลื่อนจากเธรดหลักได้โดยใช้โค้ดเพียงไม่กี่บรรทัด อะไรจะดีไปกว่า

ภาพเคลื่อนไหวบนเว็บ โดยสรุป

ภาพเคลื่อนไหวบนเว็บด้วย CSS

หากต้องการสร้างภาพเคลื่อนไหวใน CSS ให้กําหนดชุดคีย์เฟรมโดยใช้@keyframes at-rule ลิงก์กับองค์ประกอบโดยใช้พร็อพเพอร์ตี้ animation-name พร้อมกับตั้งค่า animation-duration เพื่อกำหนดระยะเวลาของภาพเคลื่อนไหว ยังมีanimation-*พร็อพเพอร์ตี้แบบเต็มanimation-easing-functionและ animation-fill-mode อีกมากมายที่รวมไว้ในanimationแบบย่อได้

ตัวอย่างเช่น ภาพเคลื่อนไหวที่ขยายองค์ประกอบในแกน X ขณะเปลี่ยนสีพื้นหลังขององค์ประกอบนั้น

@keyframes scale-up {
  from {
    background-color: red;
    transform: scaleX(0);
  }
  to {
    background-color: darkred;
    transform: scaleX(1);
  }
}

#progressbar {
  animation: 2.5s linear forwards scale-up;
}

ภาพเคลื่อนไหวบนเว็บด้วย JavaScript

ใน JavaScript คุณสามารถใช้ Web Animations API เพื่อให้ได้ผลลัพธ์แบบเดียวกัน ซึ่งทำได้โดยการสร้างอินสแตนซ์ Animation และ KeyFrameEffect ใหม่ หรือใช้เมธอด Element animate() ที่สั้นกว่ามาก

document.querySelector('#progressbar').animate(
  {
    backgroundColor: ['red', 'darkred'],
    transform: ['scaleX(0)', 'scaleX(1)'],
  },
  {
    duration: 2500,
    fill: 'forwards',
    easing: 'linear',
   }
);

ผลลัพธ์ที่แสดงผลของข้อมูลโค้ด JavaScript ด้านบนนี้เหมือนกับ CSS เวอร์ชันก่อนหน้า

ไทม์ไลน์ภาพเคลื่อนไหว

โดยค่าเริ่มต้น ภาพเคลื่อนไหวที่แนบกับองค์ประกอบจะทำงานในไทม์ไลน์ของเอกสาร เวลาเริ่มต้นคือ 0 เมื่อหน้าเว็บโหลด และเริ่มนับไปข้างหน้าตามเวลาจริง ไทม์ไลน์นี้เป็นไทม์ไลน์ภาพเคลื่อนไหวเริ่มต้น และเป็นไทม์ไลน์ภาพเคลื่อนไหวเดียวที่คุณมีสิทธิ์เข้าถึงจนถึงตอนนี้

ข้อกําหนดเฉพาะภาพเคลื่อนไหวที่ทำงานตามการเลื่อนจะกําหนดไทม์ไลน์ 2 ประเภทใหม่ที่คุณใช้ได้ ดังนี้

  • ไทม์ไลน์ความคืบหน้าในการเลื่อน: ไทม์ไลน์ที่ลิงก์กับตำแหน่งการเลื่อนของคอนเทนเนอร์การเลื่อนตามแกนใดแกนหนึ่ง
  • ดูไทม์ไลน์ความคืบหน้า: ไทม์ไลน์ที่ลิงก์กับตําแหน่งสัมพัทธ์ขององค์ประกอบหนึ่งๆ ภายในคอนเทนเนอร์การเลื่อน

เลื่อนไทม์ไลน์ความคืบหน้า

ไทม์ไลน์ความคืบหน้าในการเลื่อนคือไทม์ไลน์ภาพเคลื่อนไหวที่เชื่อมโยงกับความคืบหน้าในตำแหน่งการเลื่อนของคอนเทนเนอร์การเลื่อน ซึ่งเรียกอีกอย่างว่า scrollport หรือ scroller ตามแกนใดแกนหนึ่ง ซึ่งจะแปลงตำแหน่งในช่วงการเลื่อนเป็นเปอร์เซ็นต์ของความคืบหน้า

ตำแหน่งการเลื่อนเริ่มต้นแสดงถึงความคืบหน้า 0% และตำแหน่งการเลื่อนสิ้นสุดแสดงถึงความคืบหน้า 100% ในการแสดงภาพต่อไปนี้ คุณจะเห็นความคืบหน้านับจาก 0% ถึง 100% เมื่อเลื่อนแถบเลื่อนจากบนลงล่าง

การแสดงข้อมูลผ่านภาพไทม์ไลน์ความคืบหน้าของการเลื่อน เมื่อคุณเลื่อนไปที่ด้านล่างของแถบเลื่อน ค่าความคืบหน้าจะนับจาก 0% เป็น 100%

✨ ลองใช้ด้วยตัวคุณเอง

ไทม์ไลน์ความคืบหน้าในการเลื่อนมักจะเรียกสั้นๆ ว่า "ไทม์ไลน์การเลื่อน"

ดูไทม์ไลน์ความคืบหน้า

ไทม์ไลน์ประเภทนี้เชื่อมโยงกับความคืบหน้าแบบสัมพัทธ์ขององค์ประกอบหนึ่งๆ ภายในคอนเทนเนอร์การเลื่อน ระบบจะติดตามออฟเซตการเลื่อนของเครื่องมือเลื่อนเช่นเดียวกับไทม์ไลน์ความคืบหน้าของการเลื่อน ซึ่งต่างจากไทม์ไลน์ความคืบหน้าของการเลื่อนตรงที่ตำแหน่งสัมพัทธ์ของวัตถุภายในแถบเลื่อนนั้นเป็นตัวกำหนดความคืบหน้า

ซึ่งคล้ายกับวิธีการทำงานของ IntersectionObserver ที่ติดตามระดับการมองเห็นองค์ประกอบในแถบเลื่อน หากไม่เห็นองค์ประกอบในแถบเลื่อน แสดงว่าองค์ประกอบไม่ได้ตัดกัน หากมองเห็นส่วนใดส่วนหนึ่งขององค์ประกอบภายในแถบเลื่อน แสดงว่าองค์ประกอบนั้นตัดกัน

ไทม์ไลน์ความคืบหน้าของการดูจะเริ่มต้นจากตอนที่วัตถุเริ่มตัดกับแถบเลื่อนและสิ้นสุดเมื่อวัตถุหยุดตัดกับแถบเลื่อน ในภาพแสดงข้อมูลต่อไปนี้ คุณจะเห็นความคืบหน้าเริ่มนับจาก 0% เมื่อวัตถุเข้าคอนเทนเนอร์การเลื่อน และถึง 100% ทันทีที่วัตถุออกจากคอนเทนเนอร์การเลื่อน

การแสดงข้อมูลผ่านภาพไทม์ไลน์ความคืบหน้าของมุมมอง ความคืบหน้าจะนับจาก 0% เป็น 100% เมื่อวัตถุ (กล่องสีเขียว) ข้ามแถบเลื่อน

✨ ลองใช้ด้วยตัวคุณเอง

ไทม์ไลน์ความคืบหน้าของการดูมักเรียกสั้นๆ ว่า "ไทม์ไลน์การดู" คุณสามารถกําหนดเป้าหมายไปยังส่วนใดส่วนหนึ่งของไทม์ไลน์การดูตามขนาดของเรื่องได้ แต่เราจะพูดถึงเรื่องนี้ในภายหลัง

ใช้ประโยชน์จากไทม์ไลน์ความคืบหน้าในการเลื่อน

การสร้างไทม์ไลน์ความคืบหน้าในการเลื่อนที่ไม่ระบุตัวตนใน CSS

วิธีที่ง่ายที่สุดในการสร้างไทม์ไลน์การเลื่อนใน CSS คือการใช้ฟังก์ชัน scroll() ซึ่งจะสร้างไทม์ไลน์การเลื่อนแบบไม่ระบุตัวตนที่คุณตั้งเป็นค่าสําหรับพร็อพเพอร์ตี้ animation-timeline ใหม่ได้

ตัวอย่าง

@keyframes animate-it { … }

.subject {
  animation: animate-it linear;
  animation-timeline: scroll(root block);
}

ฟังก์ชัน scroll() ยอมรับอาร์กิวเมนต์ <scroller> และ <axis>

ค่าที่ยอมรับสำหรับอาร์กิวเมนต์ <scroller> มีดังนี้

  • nearest: ใช้คอนเทนเนอร์การเลื่อนของบรรพบุรุษที่อยู่ใกล้ที่สุด (ค่าเริ่มต้น)
  • root: ใช้วิวพอร์ตเอกสารเป็นคอนเทนเนอร์การเลื่อน
  • self: ใช้องค์ประกอบนั้นเองเป็นคอนเทนเนอร์การเลื่อน

ค่าที่ยอมรับสำหรับอาร์กิวเมนต์ <axis> มีดังนี้

  • block: ใช้การวัดความคืบหน้าตามแนวแกนบล็อกของคอนเทนเนอร์การเลื่อน (ค่าเริ่มต้น)
  • inline: ใช้การวัดความคืบหน้าตามแกนแนวนอนของคอนเทนเนอร์การเลื่อน
  • y: ใช้การวัดความคืบหน้าตามแกน Y ของคอนเทนเนอร์การเลื่อน
  • x: ใช้การวัดความคืบหน้าตามแกน x ของคอนเทนเนอร์การเลื่อน

เช่น หากต้องการเชื่อมโยงภาพเคลื่อนไหวกับตัวเลื่อนรูทบนแกนบล็อก ค่าที่จะส่งไปยัง scroll() คือ root และ block เมื่อรวมกันแล้ว ค่าที่ได้คือ scroll(root block)

ตัวอย่าง: สัญญาณบอกสถานะความคืบหน้าในการอ่าน

การสาธิตนี้มีตัวบ่งชี้ความคืบหน้าในการอ่านที่ยึดอยู่ที่ด้านบนของวิวพอร์ต เมื่อคุณเลื่อนหน้าลง แถบความคืบหน้าจะขยายจนเต็มความกว้างของวิวพอร์ตเมื่อถึงส่วนท้ายของเอกสาร ระบบจะใช้ไทม์ไลน์ความคืบหน้าในการเลื่อนแบบไม่ระบุตัวตนเพื่อขับเคลื่อนภาพเคลื่อนไหว

สาธิต: ตัวบ่งชี้ความคืบหน้าในการอ่าน

✨ ลองใช้ด้วยตัวคุณเอง

วางตัวบ่งชี้ความคืบหน้าในการอ่านที่ด้านบนของหน้าโดยใช้ตำแหน่งแบบคงที่ หากต้องการใช้ประโยชน์จากภาพเคลื่อนไหวแบบคอมโพสิต ระบบจะไม่ทำให้ width เคลื่อนไหว แต่จะทำการปรับขนาดองค์ประกอบลงบนแกน X โดยใช้ transform

<body>
  <div id="progress"></div>
  …
</body>
@keyframes grow-progress {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

#progress {
  position: fixed;
  left: 0; top: 0;
  width: 100%; height: 1em;
  background: red;

  transform-origin: 0 50%;
  animation: grow-progress auto linear;
  animation-timeline: scroll();
}

ไทม์ไลน์สำหรับภาพเคลื่อนไหว grow-progress ในองค์ประกอบ #progress ได้รับการตั้งค่าเป็นไทม์ไลน์ที่ไม่ระบุตัวตนซึ่งสร้างขึ้นโดยใช้ scroll() ไม่ได้ระบุอาร์กิวเมนต์ให้กับ scroll() ดังนั้นระบบจะใช้ค่าเริ่มต้น

แถบเลื่อนเริ่มต้นที่จะติดตามคือ nearest และแกนเริ่มต้นคือ block วิธีนี้กำหนดเป้าหมายไปยัง Scroller รูทได้อย่างมีประสิทธิภาพ เนื่องจากเป็น Scroller ที่ใกล้ที่สุดขององค์ประกอบ #progress ในขณะเดียวกันก็ติดตามทิศทางของบล็อก

การสร้างไทม์ไลน์ความคืบหน้าในการเลื่อนที่มีชื่อใน CSS

อีกวิธีในการกําหนดไทม์ไลน์ความคืบหน้าในการเลื่อนคือการใช้ไทม์ไลน์ที่มีชื่อ รูปแบบคำสั่งนี้จะแสดงรายละเอียดมากกว่า แต่อาจมีประโยชน์เมื่อคุณไม่ได้กําหนดเป้าหมายไปยัง Scroller หลักหรือ Scroller รูท หรือเมื่อหน้าเว็บใช้ไทม์ไลน์หลายรายการ หรือเมื่อการค้นหาอัตโนมัติไม่ทํางาน วิธีนี้ช่วยให้คุณระบุไทม์ไลน์ความคืบหน้าในการเลื่อนตามชื่อที่คุณตั้งไว้ได้

หากต้องการสร้างไทม์ไลน์ความคืบหน้าในการเลื่อนที่มีชื่อบนองค์ประกอบ ให้ตั้งค่าพร็อพเพอร์ตี้ scroll-timeline-name CSS ในคอนเทนเนอร์การเลื่อนเป็นตัวระบุที่ต้องการ ค่าต้องขึ้นต้นด้วย --

หากต้องการปรับแกนที่จะติดตาม ให้ประกาศพร็อพเพอร์ตี้ scroll-timeline-axis ด้วย ค่าที่อนุญาตจะเหมือนกับอาร์กิวเมนต์ <axis> ของ scroll()

สุดท้าย หากต้องการลิงก์ภาพเคลื่อนไหวกับไทม์ไลน์ความคืบหน้าของการเลื่อน ให้ตั้งค่าพร็อพเพอร์ตี้ animation-timeline ในองค์ประกอบที่ต้องแสดงภาพเคลื่อนไหวเป็นค่าเดียวกับตัวระบุที่ใช้สำหรับ scroll-timeline-name

ตัวอย่างโค้ด

@keyframes animate-it { … }

.scroller {
  scroll-timeline-name: --my-scroller;
  scroll-timeline-axis: inline;
}

.scroller .subject {
  animation: animate-it linear;
  animation-timeline: --my-scroller;
}

คุณรวม scroll-timeline-name และ scroll-timeline-axis ไว้ในตัวย่อ scroll-timeline ได้หากต้องการ เช่น

scroll-timeline: --my-scroller inline;

การสาธิตนี้แสดงตัวบ่งชี้ขั้นตอนที่แสดงเหนือภาพสไลด์แต่ละภาพ เมื่อภาพสไลด์มีรูปภาพ 3 รูป แถบตัวบ่งชี้จะเริ่มต้นที่ความกว้าง 33% เพื่อระบุว่าคุณกําลังดูรูปภาพ 1 ใน 3 อยู่ เมื่อภาพสุดท้ายปรากฏขึ้น (ซึ่งพิจารณาจากการเลื่อนแถบเลื่อนไปยังส่วนท้าย) ตัวบ่งชี้จะกินพื้นที่เต็มความกว้างของแถบเลื่อน ระบบจะใช้ไทม์ไลน์ความคืบหน้าของการเลื่อนที่มีชื่อเพื่อขับเคลื่อนภาพเคลื่อนไหว

สาธิต: ตัวบ่งชี้ขั้นตอนของภาพสไลด์แนวนอน

✨ ลองใช้ด้วยตัวคุณเอง

มาร์กอัปพื้นฐานสำหรับแกลเลอรีมีดังนี้

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

องค์ประกอบ .gallery__progress อยู่ในตําแหน่งแบบสัมบูรณ์ภายในองค์ประกอบ .gallery ขนาดเริ่มต้นจะกำหนดโดยพร็อพเพอร์ตี้ที่กำหนดเอง --num-images

.gallery {
  position: relative;
}


.gallery__progress {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 1em;
  transform: scaleX(calc(1 / var(--num-images)));
}

.gallery__scrollcontainer จะวางองค์ประกอบ .gallery__entry ที่มีในแนวนอนและเป็นองค์ประกอบที่เลื่อน .gallery__progress จะมีภาพเคลื่อนไหวเมื่อติดตามตำแหน่งการเลื่อน ซึ่งทำได้โดยการอ้างอิงไทม์ไลน์ความคืบหน้าในการเลื่อนชื่อ --gallery__scrollcontainer

@keyframes grow-progress {
  to { transform: scaleX(1); }
}

.gallery__scrollcontainer {
  overflow-x: scroll;
  scroll-timeline: --gallery__scrollcontainer inline;
}
.gallery__progress {
  animation: auto grow-progress linear forwards;
  animation-timeline: --gallery__scrollcontainer;
}

การสร้างไทม์ไลน์ความคืบหน้าในการเลื่อนด้วย JavaScript

หากต้องการสร้างไทม์ไลน์การเลื่อนใน JavaScript ให้สร้างอินสแตนซ์ใหม่ของคลาส ScrollTimeline ส่งกระเป๋าพร็อพเพอร์ตี้ที่มี source และ axis ที่ต้องการติดตาม

  • source: การอ้างอิงองค์ประกอบที่มีตัวเลื่อนที่คุณต้องการติดตาม ใช้ document.documentElement เพื่อกําหนดเป้าหมายไปยังตัวเลื่อนระดับรูท
  • axis: กำหนดแกนที่จะติดตาม ค่าที่ยอมรับคือ block, inline, x และ y ซึ่งคล้ายกับตัวแปร CSS
const tl = new ScrollTimeline({
  source: document.documentElement,
});

หากต้องการแนบกับภาพเคลื่อนไหวบนเว็บ ให้ส่งเป็นพร็อพเพอร์ตี้ timeline และละเว้น duration หากมี

$el.animate({
  opacity: [0, 1],
}, {
  timeline: tl,
});

สาธิต: สัญญาณบอกสถานะความคืบหน้าในการอ่าน (เวอร์ชันปรับปรุง)

หากต้องการสร้างตัวบ่งชี้ความคืบหน้าในการอ่านด้วย JavaScript อีกครั้งขณะใช้มาร์กอัปเดียวกัน ให้ใช้โค้ด JavaScript ต่อไปนี้

const $progressbar = document.querySelector('#progress');

$progressbar.style.transformOrigin = '0% 50%';
$progressbar.animate(
  {
    transform: ['scaleX(0)', 'scaleX(1)'],
  },
  {
    fill: 'forwards',
    timeline: new ScrollTimeline({
      source: document.documentElement,
    }),
  }
);

ผลลัพธ์ที่มองเห็นจะเหมือนกันในเวอร์ชัน CSS โดย timeline ที่สร้างขึ้นจะติดตามตัวเลื่อนรูทและปรับขนาด #progress ในแกน x จาก 0% เป็น 100% ขณะที่คุณเลื่อนหน้าเว็บ

✨ ลองใช้ด้วยตัวคุณเอง

ใช้ประโยชน์จากไทม์ไลน์ความคืบหน้าของมุมมอง

การสร้างไทม์ไลน์ความคืบหน้าของมุมมองแบบไม่ระบุตัวตนใน CSS

หากต้องการสร้างไทม์ไลน์ความคืบหน้าของมุมมอง ให้ใช้ฟังก์ชัน view() อาร์กิวเมนต์ที่ยอมรับคือ <axis> และ <view-timeline-inset>

  • <axis> เหมือนกับจากไทม์ไลน์ความคืบหน้าในการเลื่อน และกำหนดแกนที่จะติดตาม ค่าเริ่มต้นคือ block
  • เมื่อใช้ <view-timeline-inset> คุณจะระบุออฟเซ็ต (บวกหรือลบ) เพื่อปรับขอบเขตได้เมื่อระบบพิจารณาว่าองค์ประกอบอยู่ในมุมมองหรือไม่ ค่าต้องเป็นเปอร์เซ็นต์หรือ auto โดย auto เป็นค่าเริ่มต้น

เช่น หากต้องการเชื่อมโยงภาพเคลื่อนไหวกับองค์ประกอบที่ตัดกับตัวเลื่อนบนแกนบล็อก ให้ใช้ view(block) ตั้งค่านี้เป็นค่าสําหรับพร็อพเพอร์ตี้ animation-timeline เช่นเดียวกับ scroll() และอย่าลืมตั้งค่า animation-duration เป็น auto

เมื่อใช้โค้ดต่อไปนี้ img ทุกรายการจะค่อยๆ ปรากฏขึ้นเมื่อผ่านวิวพอร์ตขณะที่คุณเลื่อน

@keyframes reveal {
  from { opacity: 0; }
  to { opacity: 1; }
}

img {
  animation: reveal linear;
  animation-timeline: view();
}

ช่วงพักระหว่างบท: ดูช่วงไทม์ไลน์

โดยค่าเริ่มต้น ภาพเคลื่อนไหวที่ลิงก์กับไทม์ไลน์ของมุมมองจะแนบกับช่วงไทม์ไลน์ทั้งหมด ซึ่งจะเริ่มตั้งแต่ตอนที่วัตถุกำลังจะเข้าสู่พื้นที่เลื่อน และสิ้นสุดเมื่อวัตถุออกจากพื้นที่เลื่อนโดยสมบูรณ์

นอกจากนี้ คุณยังลิงก์กับส่วนใดส่วนหนึ่งของไทม์ไลน์ของมุมมองได้โดยระบุช่วงที่จะแนบ เช่น เฉพาะในกรณีที่วัตถุกำลังเข้าสู่แถบเลื่อน ในการแสดงภาพต่อไปนี้ ความคืบหน้าจะเริ่มนับจาก 0% เมื่อวัตถุเข้าสู่คอนเทนเนอร์การเลื่อน แต่ถึง 100% แล้วนับตั้งแต่ที่วัตถุตัดกันทั้งหมด

ไทม์ไลน์มุมมองที่ตั้งค่าให้ติดตามช่วงรายการของเรื่อง ภาพเคลื่อนไหวจะทำงานเฉพาะในขณะที่วัตถุกำลังเข้าสู่พื้นที่เลื่อน

ช่วงไทม์ไลน์ของมุมมองที่เป็นไปได้ซึ่งคุณกำหนดเป้าหมายได้มีดังนี้

  • cover: แสดงไทม์ไลน์ความคืบหน้าในการดูแบบเต็ม
  • entry: แสดงช่วงที่กล่องหลักเข้าสู่ช่วงการมองเห็นความคืบหน้าของมุมมอง
  • exit: แสดงช่วงที่กล่องหลักออกจากช่วงการมองเห็นความคืบหน้าของมุมมอง
  • entry-crossing: แสดงช่วงระหว่างที่กล่องหลักตัดผ่านขอบเส้นขอบด้านท้าย
  • exit-crossing: แสดงช่วงระหว่างที่กล่องหลักตัดผ่านขอบเส้นขอบเริ่มต้น
  • contain: แสดงช่วงระหว่างที่ช่องหลักอยู่ภายในหรือครอบคลุมช่วงการมองเห็นความคืบหน้าในการดูภายในวิวพอร์ตอย่างเต็มรูปแบบ ซึ่งขึ้นอยู่กับว่าวัตถุสูงกว่าหรือต่ำกว่าตัวเลื่อน

หากต้องการกําหนดช่วง คุณต้องตั้งค่า range-start และ range-end โดยแต่ละรายการประกอบด้วย range-name (ดูรายการด้านบน) และ range-offset เพื่อระบุตําแหน่งใน range-name นั้น โดยปกติแล้ว ช่วงการเลื่อนจะระบุเป็นเปอร์เซ็นต์ในช่วง 0% ถึง 100% แต่คุณระบุความยาวคงที่ เช่น 20em ก็ได้

เช่น หากต้องการเรียกใช้ภาพเคลื่อนไหวจากตอนที่วัตถุเข้า ให้เลือก entry 0% เป็นช่วงเริ่มต้น หากต้องการให้เสร็จสิ้นภายในเวลาที่ผู้สมัครเข้ามา ให้เลือก entry 100% เป็นค่าของ range-end

ใน CSS คุณจะตั้งค่านี้โดยใช้พร็อพเพอร์ตี้ animation-range ตัวอย่าง

animation-range: entry 0% entry 100%;

ใน JavaScript ให้ใช้พร็อพเพอร์ตี้ rangeStart และ rangeEnd

$el.animate(
  keyframes,
  {
    timeline: tl,
    rangeStart: 'entry 0%',
    rangeEnd: 'entry 100%',
  }
);

ใช้เครื่องมือที่ฝังอยู่ด้านล่างเพื่อดูว่าชื่อช่วงแต่ละรายการหมายถึงอะไร และเปอร์เซ็นต์ส่งผลต่อตําแหน่งเริ่มต้นและสิ้นสุดอย่างไร ลองตั้งค่า range-start เป็น entry 0% และ range-end เป็น cover 50% แล้วลากแถบเลื่อนเพื่อดูผลลัพธ์ของภาพเคลื่อนไหว

เครื่องมือแสดงภาพช่วงไทม์ไลน์ของมุมมอง ซึ่งดูได้ที่ https://goo.gle/view-timeline-range-tool

ดูไฟล์บันทึก

คุณอาจสังเกตเห็นขณะใช้เครื่องมือดูช่วงไทม์ไลน์นี้ว่าช่วงบางช่วงสามารถกําหนดเป้าหมายได้โดยใช้ชุดค่าผสมของชื่อช่วง + การเลื่อนช่วง 2 ชุดที่แตกต่างกัน เช่น entry 0%, entry-crossing 0% และ cover 0% ทั้งหมดกำหนดเป้าหมายเป็นพื้นที่เดียวกัน

เมื่อ range-start และ range-end กำหนดเป้าหมายไปยัง range-name เดียวกันและครอบคลุมทั้งช่วงตั้งแต่ 0% ถึง 100% คุณสามารถย่อค่าให้เหลือเพียงชื่อช่วงได้ เช่น animation-range: entry 0% entry 100%; สามารถเขียนใหม่เป็น animation-range: entry ที่สั้นกว่าได้

การสาธิต: การเปิดเผยรูปภาพ

การสาธิตนี้จะค่อยๆ แสดงรูปภาพเมื่อรูปภาพเข้าสู่พื้นที่เลื่อน ซึ่งทำได้โดยใช้ไทม์ไลน์การดูแบบไม่ระบุตัวบุคคล เราได้ปรับช่วงภาพเคลื่อนไหวเพื่อให้แต่ละภาพมีความทึบแสงเต็มที่เมื่อเลื่อนไปครึ่งทาง

สาธิต: การเปิดเผยรูปภาพ

✨ ลองใช้ด้วยตัวคุณเอง

เอฟเฟกต์การขยายจะสร้างขึ้นโดยใช้ clip-path ที่มีภาพเคลื่อนไหว CSS ที่ใช้สำหรับเอฟเฟกต์นี้คือ

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

.revealing-image {
  animation: auto linear reveal both;
  animation-timeline: view();
  animation-range: entry 25% cover 50%;
}

การสร้างไทม์ไลน์ความคืบหน้าของมุมมองที่มีชื่อใน CSS

คุณสามารถสร้างไทม์ไลน์มุมมองที่มีชื่อได้เช่นเดียวกับไทม์ไลน์การเลื่อนที่มีชื่อ คุณใช้ตัวแปรที่มีคำนำหน้า view-timeline- แทนพร็อพเพอร์ตี้ scroll-timeline-* ซึ่งได้แก่ view-timeline-name และ view-timeline-axis

ค่าประเภทเดียวกันจะมีผล และกฎเดียวกันสำหรับการค้นหาไทม์ไลน์ที่มีชื่อจะมีผล

ตัวอย่าง: การเปิดเผยรูปภาพ (เวอร์ชันปรับปรุง)

การทําการสาธิตการแสดงรูปภาพจากก่อนหน้านี้อีกครั้ง โค้ดที่แก้ไขแล้วมีลักษณะดังนี้

.revealing-image {
  view-timeline-name: --revealing-image;
  view-timeline-axis: block;

  animation: auto linear reveal both;
  animation-timeline: --revealing-image;
  animation-range: entry 25% cover 50%;
}

เมื่อใช้ view-timeline-name: revealing-image ระบบจะติดตามองค์ประกอบภายใน Scroller ที่ใกล้ที่สุด จากนั้นระบบจะใช้ค่าเดียวกันเป็นค่าสําหรับพร็อพเพอร์ตี้ animation-timeline เอาต์พุตภาพจะเหมือนกับก่อนหน้านี้ทุกประการ

✨ ลองใช้ด้วยตัวคุณเอง

การสร้างไทม์ไลน์ความคืบหน้าของมุมมองใน JavaScript

หากต้องการสร้างไทม์ไลน์มุมมองใน JavaScript ให้สร้างอินสแตนซ์ใหม่ของคลาส ViewTimeline ส่งกระเป๋าพร็อพเพอร์ตี้ที่มี subject ที่ต้องการติดตาม, axis และ inset

  • subject: การอ้างอิงองค์ประกอบที่คุณต้องการติดตามภายในตัวเลื่อนขององค์ประกอบนั้น
  • axis: แกนที่จะติดตาม ค่าที่ยอมรับคือ block, inline, x และ y ซึ่งคล้ายกับตัวแปร CSS
  • inset: การปรับแถบเลื่อน(บวก) หรือ(ลบ) ของแถบเลื่อนเมื่อพิจารณาว่ากล่องอยู่ในมุมมองหรือไม่
const tl = new ViewTimeline({
  subject: document.getElementById('subject'),
});

หากต้องการแนบกับภาพเคลื่อนไหวบนเว็บ ให้ส่งเป็นพร็อพเพอร์ตี้ timeline และละเว้น duration หากมี (ไม่บังคับ) ส่งข้อมูลช่วงโดยใช้พร็อพเพอร์ตี้ rangeStart และ rangeEnd

$el.animate({
  opacity: [0, 1],
}, {
  timeline: tl,
  rangeStart: 'entry 25%',
  rangeEnd: 'cover 50%',
});

✨ ลองใช้ด้วยตัวคุณเอง

สิ่งอื่นๆ ที่น่าลอง

การแนบกับช่วงไทม์ไลน์ของมุมมองหลายช่วงด้วยคีย์เฟรมชุดเดียว

มาดูตัวอย่างรายชื่อติดต่อนี้ที่รายการมีภาพเคลื่อนไหวกัน เมื่อรายการในรายการเข้าสู่พื้นที่เลื่อนจากด้านล่าง ระบบจะเลื่อนรายการนั้นขึ้นและทำให้ค่อยๆ ปรากฏขึ้น และเมื่อรายการออกจากพื้นที่เลื่อนที่ด้านบน ระบบจะเลื่อนรายการนั้นลงและทำให้ค่อยๆ หายไป

สาธิต: รายชื่อติดต่อ

✨ ลองใช้ด้วยตัวคุณเอง

ในการสาธิตนี้ แต่ละองค์ประกอบได้รับการตกแต่งด้วยไทม์ไลน์มุมมอง 1 รายการซึ่งติดตามองค์ประกอบขณะที่ข้ามวิวพอร์ต แต่มีภาพเคลื่อนไหวที่ทำงานตามการเลื่อน 2 รายการแนบอยู่ ภาพเคลื่อนไหว animate-in จะแนบอยู่กับช่วง entry ของไทม์ไลน์ และภาพเคลื่อนไหว animate-out จะแนบอยู่กับช่วง exit ของไทม์ไลน์

@keyframes animate-in {
  0% { opacity: 0; transform: translateY(100%); }
  100% { opacity: 1; transform: translateY(0); }
}
@keyframes animate-out {
  0% { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-100%); }
}

#list-view li {
  animation: animate-in linear forwards,
             animate-out linear forwards;
  animation-timeline: view();
  animation-range: entry, exit;
}

คุณสามารถสร้างคีย์เฟรมชุดเดียวที่มีข้อมูลช่วงอยู่แล้วแทนที่จะแสดงภาพเคลื่อนไหว 2 แบบที่แตกต่างกันซึ่งเชื่อมโยงกับ 2 ช่วงที่แตกต่างกัน

@keyframes animate-in-and-out {
  entry 0%  {
    opacity: 0; transform: translateY(100%);
  }
  entry 100%  {
    opacity: 1; transform: translateY(0);
  }
  exit 0% {
    opacity: 1; transform: translateY(0);
  }
  exit 100% {
    opacity: 0; transform: translateY(-100%);
  }
}

#list-view li {
  animation: linear animate-in-and-out;
  animation-timeline: view();
}

เนื่องจากคีย์เฟรมมีข้อมูลช่วง คุณจึงไม่จำเป็นต้องระบุ animation-range ผลลัพธ์ที่ได้จะเหมือนกับก่อนหน้านี้ทุกประการ

✨ ลองใช้ด้วยตัวคุณเอง

การแนบกับไทม์ไลน์การเลื่อนที่ไม่ใช่บรรพบุรุษ

กลไกการค้นหาสำหรับไทม์ไลน์การเลื่อนที่มีชื่อและไทม์ไลน์มุมมองที่มีชื่อจะจำกัดอยู่ที่บรรพบุรุษของการเลื่อนเท่านั้น แต่บ่อยครั้ง องค์ประกอบที่ต้องเคลื่อนไหวนั้นไม่ได้เป็นองค์ประกอบย่อยของ Scroller ที่ต้องติดตาม

พร็อพเพอร์ตี้ timeline-scope จะเข้ามามีบทบาทเพื่อให้การดำเนินการนี้ทำงานได้ คุณใช้พร็อพเพอร์ตี้นี้เพื่อประกาศไทม์ไลน์ที่มีชื่อนั้นโดยไม่ต้องสร้างจริง วิธีนี้จะทำให้ลำดับเวลาที่ชื่อนั้นๆ มีขอบเขตที่กว้างขึ้น ในทางปฏิบัติ คุณจะใช้พร็อพเพอร์ตี้ timeline-scope ในองค์ประกอบหลักที่แชร์เพื่อให้ไทม์ไลน์ของแถบเลื่อนย่อยแนบกับองค์ประกอบหลักได้

เช่น

.parent {
  timeline-scope: --tl;
}
.parent .scroller {
  scroll-timeline: --tl;
}
.parent .scroller ~ .subject {
  animation: animate linear;
  animation-timeline: --tl;
}

ในข้อมูลโค้ดนี้

  • องค์ประกอบ .parent ประกาศไทม์ไลน์ที่มีชื่อ --tl องค์ประกอบย่อยขององค์ประกอบดังกล่าวจะค้นหาและใช้ค่าดังกล่าวเป็นค่าของพร็อพเพอร์ตี้ animation-timeline ได้
  • องค์ประกอบ .scroller กำหนดไทม์ไลน์การเลื่อนที่มีชื่อว่า --tl โดยค่าเริ่มต้น เฉพาะบุตรหลานของ .parent เท่านั้นที่จะมองเห็นได้ แต่เนื่องจาก .parent ตั้งค่าเป็น scroll-timeline-root .parent จึงแนบอยู่กับ scroll-timeline-root
  • องค์ประกอบ .subject ใช้ไทม์ไลน์ --tl รายการดังกล่าวจะเดินขึ้นลําดับชั้นบรรพบุรุษและพบ --tl ใน .parent เมื่อ --tl ใน .parent ชี้ไปที่ --tl ของ .scroller .subject จะติดตามไทม์ไลน์ความคืบหน้าในการเลื่อนของ .scroller

กล่าวคือ คุณสามารถใช้ timeline-root เพื่อย้ายไทม์ไลน์ไปยังบรรพบุรุษ (หรือที่เรียกว่าการยกระดับ) เพื่อให้บรรพบุรุษและรายการย่อยทั้งหมดเข้าถึงไทม์ไลน์นั้นได้

พร็อพเพอร์ตี้ timeline-scope ใช้ได้ทั้งกับไทม์ไลน์การเลื่อนและไทม์ไลน์มุมมอง

การสาธิตและแหล่งข้อมูลเพิ่มเติม

แสดงตัวอย่างทั้งหมดในบทความนี้ในมินิไซต์ scroll-driven-animations.style เว็บไซต์มีตัวอย่างอีกมากมายเพื่อแสดงให้เห็นว่าภาพเคลื่อนไหวที่ทำงานตามการเลื่อนทำได้หลายอย่าง

ตัวอย่างเพลงอื่นๆ อย่างหนึ่งคือรายการภาพปกอัลบั้มนี้ โดยภาพปกแต่ละภาพจะหมุนเป็น 3 มิติขณะอยู่ในจุดสนใจตรงกลาง

สาธิต: Cover Flow

✨ ลองใช้ด้วยตัวคุณเอง

หรือดูการสาธิตการซ้อนการ์ดนี้ที่ใช้ประโยชน์จาก position: sticky เมื่อการ์ดซ้อนกัน การ์ดที่วางไว้แล้วจะมีขนาดลดลง ซึ่งจะสร้างเอฟเฟกต์ความลึกที่น่าสนใจ สุดท้ายแล้ว กองภาพทั้งหมดจะเลื่อนออกไปจากมุมมองพร้อมกัน

สาธิต: การซ้อนการ์ด

✨ ลองใช้ด้วยตัวคุณเอง

นอกจากนี้ scroll-driven-animations.style ยังมีคอลเล็กชันเครื่องมือ เช่น ภาพแสดงผลความคืบหน้าของช่วงไทม์ไลน์ของมุมมองที่รวมอยู่ในโพสต์นี้ก่อนหน้านี้

ภาพเคลื่อนไหวที่ทำงานตามการเลื่อนยังอยู่ในหัวข้อมีอะไรใหม่ในภาพเคลื่อนไหวบนเว็บที่ Google I/O ’23 ด้วย