เอฟเฟกต์ภาพสไลด์แบบภาพหมุนเป็นวิธีที่ยอดเยี่ยมในการเพิ่มความน่าสนใจให้กับภาพหมุน ขณะที่ผู้ใช้เลื่อนดูสไลด์ สไลด์แต่ละรายการจะเคลื่อนไหวได้เมื่อเข้าสู่ กึ่งกลาง และออกจากพอร์ตการเลื่อน เช่น สไลด์สามารถจางเข้าและออก หมุน หรือปรับขนาดได้ ซึ่งจะช่วยสร้างประสบการณ์ของผู้ใช้ที่น่าสนใจและมีการเปลี่ยนแปลงตลอดเวลา เอฟเฟกต์นี้แตกต่างจากภาพเคลื่อนไหวเข้า/ออกแบบง่ายๆ ตรงที่ใช้ภาพเคลื่อนไหวต่อเนื่องเพียงภาพเดียวเพื่อควบคุมลักษณะที่ปรากฏของสไลด์ในพอร์ตการเลื่อนทั้งหมด
วิธีการนำไปใช้งาน
วิธีสร้างเอฟเฟกต์ภาพสไลด์แบบภาพสไลด์มีดังนี้
สร้างแถบเลื่อน: องค์ประกอบนี้จะทำหน้าที่เป็นคอนเทนเนอร์สำหรับสไลด์ภาพสไลด์ ในตัวอย่างนี้ ระบบจะใช้
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; }กำหนดภาพเคลื่อนไหว: สร้างภาพเคลื่อนไหว CSS ที่กำหนดสถานะต่างๆ ของสไลด์ขณะเลื่อนผ่านพอร์ตการเลื่อน คุณสามารถกำหนดคีย์เฟรมสำหรับส่วนใดก็ได้ของภาพเคลื่อนไหว เช่น คุณสามารถกำหนดสถานะเมื่อสไลด์อยู่ตรงกลางของ Scrollport โดยรวมคีย์เฟรม
50%ในตัวอย่างนี้ พร็อพเพอร์ตี้scaleจะทำให้สไลด์ขยายใหญ่ขึ้นเมื่อเข้าใกล้ตรงกลางและเล็กลงเมื่อเลื่อนออกไป@keyframes animate { 0% { scale: 0.5; } 50% { scale: 1; } 100% { scale: 0.5; } }ใช้ภาพเคลื่อนไหวและ
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();
}