ส่วนหัวที่หดลงเมื่อเลื่อน

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

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

วิธีสร้างส่วนหัวที่หดลงเมื่อเลื่อนมีดังนี้

  1. สร้างส่วนหัวแบบคงที่: เริ่มต้นด้วยองค์ประกอบส่วนหัวที่คงที่ที่ด้านบนของหน้าและมีความสูงที่กำหนดไว้ล่วงหน้า

    <header>HEADER</header>
    
    header {
      position: fixed;
      height: 200px;
      top: 0;
      left: 0;
      right: 0;
    }
    
  2. กำหนดภาพเคลื่อนไหวการหด: สร้างภาพเคลื่อนไหว CSS ที่เปลี่ยนความสูงของส่วนหัว

    @keyframes shrink {
      to {
        height: 50px;
      }
    }
    
  3. ใช้ภาพเคลื่อนไหวและไทม์ไลน์การเลื่อน: แนบภาพเคลื่อนไหวกับส่วนหัวและใช้ฟังก์ชัน scroll() เพื่อลิงก์กับตำแหน่งการเลื่อนของเอกสาร

    header {
      animation: shrink auto linear both;
      animation-timeline: scroll(block root);
    }
    
  4. ตั้งค่า animation-range: ใช้พร็อพเพอร์ตี้ animation-range เพื่อระบุระยะการเลื่อนที่ควรแสดงภาพเคลื่อนไหว เช่น หากต้องการย่อส่วนหัวเมื่อเลื่อนผ่าน 150 พิกเซลแรก ให้ใช้ animation-range: 0px 150px;

    header {
      animation-range: 0px 150px;
    }
    

เคล็ดลับ: หากต้องการป้องกันไม่ให้เนื้อหาที่อยู่หลังส่วนหัวถูกบดบัง ให้เพิ่ม padding-top ลงใน body (หรือคอนเทนเนอร์เนื้อหาหลัก) ที่เท่ากับความสูงเริ่มต้นของส่วนหัว

เคล็ดลับ: หากต้องการให้เนื้อหาของหน้าเลื่อนไปพร้อมกับส่วนหัวที่หดลง ให้ตั้งค่า animation-range-end เป็นความแตกต่างระหว่างขนาดเริ่มต้นและขนาดสิ้นสุด วิธีนี้ช่วยให้มั่นใจว่าภาพเคลื่อนไหวจะเสร็จสมบูรณ์เมื่อส่วนหัวมีขนาดสุดท้ายพอดี ในการสาธิตนี้ ส่วนหัวจะหดจาก 200px เป็น 50px ดังนั้น animation-range-end จึงตั้งค่าเป็น 150px

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

@keyframes shrink {
  to {
    height: 50px;
  }
}

header {
  animation: shrink auto linear both;
  animation-timeline: scroll(block root);
  animation-range: 0px 150px;
}

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

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

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

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

  • ไม่บังคับ ระบุตัวเลื่อนอย่างชัดเจน: เมื่อไม่ได้กำหนดเป้าหมายตัวเลื่อนระดับบนสุดที่ใกล้ที่สุด ให้ระบุตัวเลื่อนที่ต้องการใช้อย่างชัดเจนด้วย scroll(root) หรือ scroll(self)
    • เมื่อ root, nearest หรือ self ไม่เพียงพอ ให้ใช้ scroll-timeline ที่มีชื่อ
  • ไม่บังคับ ระบุแกนที่จะติดตามอย่างชัดเจน: เมื่อไม่ได้กำหนดเป้าหมายแกน block เริ่มต้น (เช่น ในแถบเลื่อนแนวนอน) ให้ระบุแกนที่จะติดตามอย่างชัดเจนด้วย scroll(block) หรือ scroll(inline)

สำหรับกรณีการใช้งานนี้โดยเฉพาะ

  • องค์ประกอบที่คุณทำให้เคลื่อนไหวต้องไม่ใช่ position: static หรือ position: relative เมื่อใช้เปอร์เซ็นต์ใน animation-range
    • เนื่องจากองค์ประกอบเหล่านั้นถือว่า "อยู่ในโฟลว์" การย่อองค์ประกอบเหล่านั้นขณะเลื่อนจะลดระยะทางการเลื่อนทั้งหมด ซึ่งส่งผลต่อค่าที่คำนวณได้ เช่น 10% ในการเลื่อน

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

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

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

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

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

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

// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: scroll()) and (animation-range: 0% 100%)')) {
  const header = document.querySelector('header');

  const initialHeight = 200;
  const finalHeight = 50;
  const scrollDistance = 150;

  window.addEventListener('scroll', () => {
    const scrollY = window.scrollY;
    const scrollPercent = Math.min(1, scrollY / scrollDistance);
    const newHeight = initialHeight - (initialHeight - finalHeight) * scrollPercent;

    header.style.height = `${newHeight}px`;
  });
}