สร้างเอฟเฟกต์สไลด์แบบภาพสไลด์

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

วิธีการนำไปใช้งาน

วิธีสร้างเอฟเฟกต์ภาพสไลด์แบบภาพสไลด์มีดังนี้

  1. สร้างแถบเลื่อน: องค์ประกอบนี้จะทำหน้าที่เป็นคอนเทนเนอร์สำหรับสไลด์ภาพสไลด์ ในตัวอย่างนี้ ระบบจะใช้ overflow-x: scroll เพื่ออนุญาตให้เลื่อนในแนวนอน

    <ul class="scroller">
      <li class="entry">1</li>
      <li class="entry">2</li>
      <li class="entry">3</li>
      …
    </ul>
    
    .scroller {
      overflow-x: scroll;
    }
    
  2. กำหนดภาพเคลื่อนไหว: สร้างภาพเคลื่อนไหว CSS ที่กำหนดสถานะต่างๆ ของสไลด์ขณะเลื่อนผ่านพอร์ตการเลื่อน คุณสามารถกำหนดคีย์เฟรมสำหรับส่วนใดก็ได้ของภาพเคลื่อนไหว เช่น คุณสามารถกำหนดสถานะเมื่อสไลด์อยู่ตรงกลางของ Scrollport โดยรวมคีย์เฟรม 50% ในตัวอย่างนี้ พร็อพเพอร์ตี้ scale จะทำให้สไลด์ขยายใหญ่ขึ้นเมื่อเข้าใกล้ตรงกลางและเล็กลงเมื่อเลื่อนออกไป

    @keyframes animate {
      0% {
        scale: 0.5;
      }
      50% {
        scale: 1;
      }
      100% {
        scale: 0.5;
      }
    }
    
  3. ใช้ภาพเคลื่อนไหวและ view-timeline: แนบภาพเคลื่อนไหวกับสไลด์ภาพสไลด์และลิงก์กับ view-timeline ที่ติดตามองค์ประกอบขณะเลื่อนผ่านคอนเทนเนอร์

    .scroller > * {
      animation: animate auto linear both;
      animation-timeline: view(inline);
    }
    

    โดยค่าเริ่มต้น view() จะติดตามองค์ประกอบบนแกน block หากต้องการติดตามบนแกน inline คุณสามารถใช้ view(inline) ได้

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

โค้ดนี้จะทำให้รายการภาพสไลด์ของแถบเลื่อนแนวนอนเคลื่อนไหวเมื่อเลื่อนโดยใช้ view-timeline แบบไม่ระบุชื่อ

@keyframes animate {
  0% {
    scale: 0.5;
  }

  50% {
    scale: 1;
  }

  100% {
    scale: 0.5;
  }
}

.scroller > * {
  /* Applies the animation using an `auto` duration */
  animation: animate auto linear both;
  /* Sets the animation timeline to use an anonymous view progress timeline, tracking the element's progress through the scroller on the inline axis */
  animation-timeline: view(inline);
}

โค้ดนี้จะทำให้รายการภาพสไลด์ของแถบเลื่อนแนวนอนเคลื่อนไหวเมื่อเลื่อนโดยใช้ view-timeline ที่มีชื่อ

@keyframes animate {
  0% {
    scale: 0.5;
  }

  50% {
    scale: 1;
  }

  100% {
    scale: 0.5;
  }
}

/* This creates a named view-timeline on each carousel item. The timeline is used to drive the animation that is applied on the same element. */
.scroller > * {
  /* Applies the animation using an `auto` duration */
  animation: animate auto linear both;
  /* Defines a named view progress timeline, tracking the element's progress through the scroller on the inline axis */
  view-timeline: --item inline;
  /* Sets the animation timeline to use the named view progress timeline defined above */
  animation-timeline: --item;
}

แนวทางปฏิบัติแนะนำ

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

  • ควรรวมการตรวจหาฟีเจอร์: เบราว์เซอร์บางรายการไม่รองรับภาพเคลื่อนไหวที่ขับเคลื่อนด้วยการเลื่อน ใช้ @supports ((animation-timeline: view()) and (animation-range: entry)) เพื่อตรวจสอบการรองรับและระบุตัวเลือกสำรองสำหรับเบราว์เซอร์ที่ไม่รองรับ
    • ต้องรวมการตรวจสอบ (animation-range: entry) ไว้ที่นี่เพื่อกรองเบราว์เซอร์ที่รองรับเพียงบางส่วนออก
    • อย่าใช้แพ็กเกจ scroll-timeline-polyfill สำหรับกลยุทธ์สำรอง เนื่องจากฟีเจอร์ยังไม่สมบูรณ์และมีปัญหาที่ทราบอยู่แล้วจำนวนมาก
    • หากภาพเคลื่อนไหวถือเป็นเพียงการตกแต่ง ให้เลือกใช้การเพิ่มประสิทธิภาพแบบต่อเนื่อง และอย่าระบุทางเลือกสำรอง
  • ควรเคารพค่ากำหนดของผู้ใช้: ผู้ใช้บางรายต้องการให้มีการเคลื่อนไหวน้อยลงบนเว็บ ใช้คิวรีสื่อ prefers-reduced-motion เพื่อปิดใช้หรือลดภาพเคลื่อนไหวสำหรับผู้ใช้เหล่านี้
  • ควรพยายามทำให้เฉพาะพร็อพเพอร์ตี้ CSS ที่มีประสิทธิภาพเคลื่อนไหว: เพื่อให้ภาพเคลื่อนไหวราบรื่นที่สุด ให้ใช้พร็อพเพอร์ตี้ที่เคลื่อนไหวซึ่งจัดการได้โดยเทรด Compositor ของเบราว์เซอร์ เช่น transform และ opacity การทำให้พร็อพเพอร์ตี้อื่นๆ เช่น width หรือ height เคลื่อนไหวอาจทำให้เกิดปัญหาด้านประสิทธิภาพ
  • ควรใช้ลำดับการประกาศที่ถูกต้อง: เมื่อใช้พร็อพเพอร์ตี้ชวเลข animation ให้ประกาศ animation-timeline และ animation-range หลังจากพร็อพเพอร์ตี้ดังกล่าวเพื่อป้องกันไม่ให้ชวเลขรีเซ็ตไทม์ไลน์

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

เมื่อใช้ฟังก์ชัน view() เพื่อสร้างภาพเคลื่อนไหวที่ขับเคลื่อนด้วยการเลื่อน ให้ทำดังนี้

  • ไม่บังคับ ระบุแกนที่จะติดตามอย่างชัดเจน: เมื่อไม่ได้กำหนดเป้าหมายแกน block เริ่มต้น (เช่น ในแถบเลื่อนแนวนอน) ให้ระบุแกนที่จะติดตามอย่างชัดเจนด้วย view(block) หรือ view(inline)

เมื่อใช้พร็อพเพอร์ตี้ view-timeline เพื่อสร้างภาพเคลื่อนไหวที่ขับเคลื่อนด้วยการเลื่อน ให้ทำดังนี้

  • ควรใช้ <dashed-ident> ของ CSS สำหรับชื่อ (เช่น view-timeline: --my-custom-name)
  • ไม่บังคับ ระบุแกนที่จะติดตามอย่างชัดเจน: เมื่อไม่ได้กำหนดเป้าหมายแกน block เริ่มต้น (เช่น ในแถบเลื่อนแนวนอน) ให้ระบุแกนที่จะติดตามด้วย view-timeline-axis อย่างชัดเจน
  • ควรตรวจสอบว่าขอบเขตของการค้นหาใช้งานได้: เมื่อองค์ประกอบที่ประกาศ view-timeline ไม่ใช่ระดับบนสุดแบบ Flat Tree ขององค์ประกอบที่เคลื่อนไหว ให้เพิ่มระดับการมองเห็นชื่อของ view-timeline โดยใช้ timeline-scope ในระดับบนสุดที่ใช้ร่วมกัน

การรองรับเบราว์เซอร์และกลยุทธ์สำรอง

ดังนั้น โดยทั่วไปจึงต้องมีกลยุทธ์สำรอง

สำหรับเบราว์เซอร์ที่ไม่รองรับภาพเคลื่อนไหวที่ขับเคลื่อนด้วยการเลื่อน คุณสามารถใช้โหมดสำรองเพื่อสร้างเอฟเฟกต์ภาพขึ้นมาใหม่ได้ โดยปกติแล้ว ฟังก์ชันสำรองจะสร้างขึ้นด้วย Listener การเลื่อน (สำหรับเอฟเฟกต์ ScrollTimeline) หรือ IntersectionObserver API (สำหรับเอฟเฟกต์ ViewTimeline)

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

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

สำหรับ Use Case นี้โดยเฉพาะ สคริปต์ต่อไปนี้จะใช้โหมดสำรองสำหรับเบราว์เซอร์ที่ไม่รองรับภาพเคลื่อนไหวที่ขับเคลื่อนด้วยการเลื่อน โดยใช้ Web Animations API (Element.animate()) เพื่อสร้างภาพเคลื่อนไหวที่หยุดชั่วคราวสำหรับแต่ละรายการในภาพสไลด์ จากนั้นจะฟังเหตุการณ์ scroll ในแถบเลื่อนและอัปเดต currentTime ของภาพเคลื่อนไหวแต่ละรายการตามความคืบหน้าในการเลื่อนของรายการภายในแถบเลื่อน

// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: view()) and (animation-range: entry)')) {
  const scroller = document.querySelector('.scroller');
  const entries = document.querySelectorAll('.entry');

  // Create a map to store animations
  const animations = new Map();

  entries.forEach(entry => {
    const animation = entry.animate(
      {
        scale: ['0.5', '1', '0.5']
      },
      {
        duration: 1, // We'll control the time ourselves
        fill: 'both'
      }
    );
    animation.pause();
    animations.set(entry, animation);
  });

  // Update animations on scroll
  const tick = () => {
    const scrollerRect = scroller.getBoundingClientRect();

    entries.forEach(entry => {
      const animation = animations.get(entry);
      if (!animation) return;

      const entryRect = entry.getBoundingClientRect();
      const progress = (entryRect.left + entryRect.width / 2 - scrollerRect.left) / scrollerRect.width;

      animation.currentTime = progress;
    });
  };
    
  scroller.addEventListener('scroll', tick);
  tick();
}