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

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

ภาพเคลื่อนไหวแบบเลื่อน

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

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

แหล่งที่มา

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

สัญญาณบอกสถานะการอ่านอยู่บนเอกสารซึ่งขับเคลื่อนโดยการเลื่อน

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

รูปภาพในหน้านี้จะจางลงเมื่อปรากฏให้เห็น

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

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

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

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

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

ภาพเคลื่อนไหวบนเว็บ สรุปสั้นๆ

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

หากต้องการสร้างภาพเคลื่อนไหวใน CSS ให้กำหนดชุดคีย์เฟรมโดยใช้กฎ @keyframes ลิงก์องค์ประกอบกับองค์ประกอบโดยใช้พร็อพเพอร์ตี้ 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 การดำเนินการนี้จะกำหนดเป้าหมายแถบเลื่อนรูทได้อย่างมีประสิทธิภาพ เนื่องจากเป็นตัวเลื่อนที่อยู่ใกล้ที่สุดขององค์ประกอบ #progress ขณะที่ติดตามทิศทางการบล็อกของรายการนั้น

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

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

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

หากต้องการปรับแต่งแกนที่จะติดตาม ให้ประกาศพร็อพเพอร์ตี้ 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% เพื่อบ่งบอกว่าคุณกำลังดูรูปภาพหนึ่งใน 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 อยู่ในตำแหน่งสัมบูรณ์ภายในองค์ประกอบ Wrapper .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,
});

หากต้องการแนบกับ Web Animation ส่งเข้ามาเป็นพร็อพเพอร์ตี้ 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) คล้ายกับ scroll() ให้ตั้งเป็นค่าสำหรับพร็อพเพอร์ตี้ animation-timeline และอย่าลืมตั้งค่า animation-duration เป็น auto

เมื่อใช้รหัสต่อไปนี้ img ทุกรายการจะค่อยๆ จางลงเมื่อข้ามวิวพอร์ตในขณะที่คุณเลื่อน

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

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

Intermezzo: ดูช่วงไทม์ไลน์

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

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

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

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

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

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

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

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

animation-range: entry 0% entry 100%;

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

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

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

ดูส่วน Visualizer ของมุมมองไทม์ไลน์ได้ที่ https://goo.gle/view-timeline-range-tool

ดูวิดีโอที่บันทึกไว้

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

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

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

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

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

✨ ลองด้วยตัวเองเลย

เอฟเฟกต์การขยายนั้นทำได้โดยใช้เส้นทางคลิปที่เป็นภาพเคลื่อนไหว 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

คุณยังสร้าง "ดูไทม์ไลน์" ที่มีชื่อได้เช่นเดียวกับชื่อ "ไทม์ไลน์ของการเลื่อน" แทนที่จะใช้พร็อพเพอร์ตี้ scroll-timeline-* คุณจะใช้ตัวแปรที่มีคำนำหน้า view-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 ระบบจะติดตามองค์ประกอบภายในแถบเลื่อนที่อยู่ใกล้ที่สุด จากนั้นระบบจะใช้ค่าเดียวกันนี้เป็นค่าของพร็อพเพอร์ตี้ animation-timeline เอาต์พุตภาพจะไม่เหมือนกับก่อนหน้านี้

✨ ลองด้วยตัวเองเลย

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

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

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

หากต้องการแนบกับ Web Animation ส่งเข้ามาเป็นพร็อพเพอร์ตี้ 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 ช่วงที่ต่างกัน คุณยังสามารถสร้างชุดคีย์เฟรม 1 ชุดที่มีข้อมูลของช่วงอยู่แล้วได้อีกด้วย

@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 ผลลัพธ์ที่ได้ยังคงเหมือนเดิมทุกประการ

✨ ลองด้วยตัวเองเลย

การแนบกับไทม์ไลน์การเลื่อนที่ไม่ใช่ระดับบน

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

คุณต้องนำพร็อพเพอร์ตี้ 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 ได้ตั้งค่าเป็น scroll-timeline-root จึงเชื่อมโยงด้วย
  • องค์ประกอบ .subject ใช้ไทม์ไลน์ --tl มันเดินขึ้นต้นบรรพบุรุษและพบ --tl บน .parent เนื่องจาก --tl บน .parent ชี้ไปยัง --tl ของ .scroller .subject จะติดตามไทม์ไลน์ความคืบหน้าในการเลื่อนของ .scroller

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

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

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

การสาธิตทั้งหมดที่พูดถึงในบทความนี้ที่ the Scroll-animations.style mini-site เว็บไซต์ดังกล่าวมีการสาธิตอีกมากมายเพื่อเน้นสิ่งที่เป็นไปได้ด้วยภาพเคลื่อนไหวที่ขับเคลื่อนด้วยการเลื่อน

การสาธิตเพิ่มเติมอีกอย่างหนึ่งคือรายการปกอัลบั้มนี้ หน้าปกแต่ละฉบับจะหมุนเป็น 3 มิติเมื่อถ่ายจุดกึ่งกลาง

การสาธิต: ขั้นตอนการคัฟเวอร์

✨ ลองด้วยตัวเองเลย

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

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

✨ ลองด้วยตัวเองเลย

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

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