ภาพเคลื่อนไหวเป็นส่วนสําคัญของประสบการณ์การใช้งานแบบดิจิทัล ซึ่งนําผู้ใช้จากการโต้ตอบหนึ่งไปยังอีกการโต้ตอบหนึ่ง แต่ภาพเคลื่อนไหวที่ราบรื่นบนแพลตฟอร์มเว็บมีช่องว่างอยู่บ้าง ซึ่งรวมถึงความสามารถในการสร้างภาพเคลื่อนไหวขององค์ประกอบที่ปรากฏและหายไปได้อย่างง่ายดาย รวมถึงสร้างภาพเคลื่อนไหวจากเลเยอร์บนสุดไปยังเลเยอร์บนสุดและกลับได้อย่างราบรื่นสำหรับองค์ประกอบที่ปิดได้ เช่น กล่องโต้ตอบและป๊อปอัป
Chrome เวอร์ชัน 116 และ 117 จึงมีฟีเจอร์ใหม่ 4 รายการสำหรับแพลตฟอร์มเว็บ ซึ่งช่วยให้ภาพเคลื่อนไหวและการเปลี่ยนผ่านของพร็อพเพอร์ตี้แบบแยกต่างหากเป็นไปอย่างราบรื่น
ฟีเจอร์ใหม่ 4 รายการนี้ ได้แก่
- ความสามารถในการทำให้
display
และcontent-visibility
เคลื่อนไหวในไทม์ไลน์คีย์เฟรม (จาก Chrome 116) - พร็อพเพอร์ตี้
transition-behavior
ที่มีคีย์เวิร์ดallow-discrete
เพื่อเปิดใช้การเปลี่ยนพร็อพเพอร์ตี้แบบไม่ต่อเนื่อง เช่นdisplay
(จาก Chrome 117) - กฎ
@starting-style
เพื่อให้เอฟเฟกต์รายการเคลื่อนไหวจากdisplay: none
ไปยังเลเยอร์บนสุด (จาก Chrome 117) - พร็อพเพอร์ตี้
overlay
เพื่อควบคุมลักษณะการทํางานของเลเยอร์บนสุดระหว่างภาพเคลื่อนไหว (จาก Chrome 117)
แสดงภาพเคลื่อนไหวในคีย์เฟรม
จาก Chrome 116 คุณจะใช้ display
และ content-visibility
ในกฎคีย์เฟรมได้ จากนั้นระบบจะสลับภาพเหล่านี้เมื่อเกิดคีย์เฟรม คุณไม่จำเป็นต้องใช้ค่าใหม่เพิ่มเติมเพื่อรองรับการดำเนินการนี้
.card {
animation: fade-out 0.5s forwards;
}
@keyframes fade-out {
100% {
opacity: 0;
display: none;
}
}
ตัวอย่างก่อนหน้านี้ทำให้ความทึบแสงเป็น 0 ในช่วงเวลา 0.5 วินาที จากนั้นตั้งค่าการแสดงผลเป็น ไม่มี นอกจากนี้ คีย์เวิร์ด forwards
ยังช่วยให้ภาพเคลื่อนไหวอยู่ในสถานะสุดท้าย เพื่อให้องค์ประกอบที่ใช้อยู่ยังคงเป็น display: none
และ opacity: 0
นี่เป็นตัวอย่างง่ายๆ ที่จำลองสิ่งที่คุณทําได้โดยใช้ทรานซิชัน (ดูการสาธิตในส่วนทรานซิชัน) อย่างไรก็ตาม ทรานซิชันไม่สามารถสร้างภาพเคลื่อนไหวที่ซับซ้อนมากขึ้นได้ เช่น ตัวอย่างต่อไปนี้
.card {
animation: spin-and-delete 1s ease-in forwards;
}
@keyframes spin-and-delete {
0% {
transform: rotateY(0);
filter: hue-rotate(0);
}
80% {
transform: rotateY(360deg);
filter: hue-rotate(180deg);
opacity: 1;
}
100% {
opacity: 0;
display: none;
}
}
ภาพเคลื่อนไหว spin-and-delete
คือภาพเคลื่อนไหวเมื่อออก ก่อนอื่น การ์ดจะหมุนบนแกน y ผ่านการเปลี่ยนสี จากนั้นที่ 80%
ในไทม์ไลน์ ความทึบของการ์ดจะเปลี่ยนจาก 1 เป็น 0 สุดท้าย การ์ดจะเปลี่ยนจาก display: block
เป็น display: none
สำหรับภาพเคลื่อนไหวเมื่อออกเหล่านี้ คุณสามารถตั้งค่าทริกเกอร์สำหรับภาพเคลื่อนไหวแทนที่จะใช้กับองค์ประกอบโดยตรง ตัวอย่างเช่น แนบ Listener เหตุการณ์ไว้ในปุ่มที่เรียกให้ชั้นเรียนใช้ภาพเคลื่อนไหว เช่น
.spin-out {
animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
document.querySelector('.card').classList.add('spin-out');
})
ตอนนี้ตัวอย่างข้างต้นมีสถานะสุดท้ายเป็น display:none
มีหลายกรณีที่คุณอาจต้องดำเนินการเพิ่มเติมและนำโหนด DOM ออกด้วยการกำหนดเวลาหมดอายุเพื่อให้ภาพเคลื่อนไหวเล่นจนจบก่อน
การเปลี่ยนภาพเคลื่อนไหวแบบไม่ต่อเนื่อง
หากต้องการเปลี่ยนคุณสมบัติที่แยกกัน คุณจะต้องใช้โหมดลักษณะการเปลี่ยน allow-discrete
ซึ่งต่างจากการสร้างภาพเคลื่อนไหวของคุณสมบัติที่ไม่ต่อเนื่องด้วยคีย์เฟรม
พร็อพเพอร์ตี้ transition-behavior
โหมด allow-discrete
คือสิ่งที่ทำให้คุณเปลี่ยนการใช้งานแบบไม่ต่อเนื่องได้ และเป็นค่าของพร็อพเพอร์ตี้ transition-behavior
transition-behavior
ยอมรับค่า 2 ค่า ได้แก่ normal
และ allow-discrete
.card {
transition: opacity 0.25s, display 0.25s;
transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}
.card.fade-out {
opacity: 0;
display: none;
}
ตัวย่อ transition
จะตั้งค่านี้ด้วย คุณจึงละเว้นพร็อพเพอร์ตี้และใช้คีย์เวิร์ด allow-discrete
ที่ท้ายตัวย่อ transition
สำหรับทรานซิชันแต่ละรายการแทนได้
.card {
transition: opacity 0.5s, display 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
หากต้องการสร้างภาพเคลื่อนไหวให้กับพร็อพเพอร์ตี้แบบแยกหลายรายการ คุณจะต้องใส่ allow-discrete
หลังพร็อพเพอร์ตี้แต่ละรายการที่ต้องการสร้างภาพเคลื่อนไหว เช่น
.card {
transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
กฎ @starting-style
สำหรับรายการภาพเคลื่อนไหว
จนถึงตอนนี้ บทความนี้กล่าวถึงภาพเคลื่อนไหวที่ออกแล้ว หากต้องการสร้างภาพเคลื่อนไหวที่เข้ามา คุณจะต้องใช้กฎ @starting-style
ใช้ @starting-style
เพื่อใช้สไตล์ที่เบราว์เซอร์ค้นหาได้ก่อนที่องค์ประกอบจะเปิดในหน้า นี่คือสถานะ "ก่อนเปิด" (ตำแหน่งที่คุณเริ่มแสดงภาพเคลื่อนไหว)
/* 0. IS-OPEN STATE */
/* The state at which the element is open + transition logic */
.item {
height: 3rem;
display: grid;
overflow: hidden;
transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}
/* 1. BEFORE-OPEN STATE */
/* Starting point for the transition */
@starting-style {
.item {
opacity: 0;
height: 0;
}
}
/* 2. EXITING STATE */
/* While it is deleting, before DOM removal in JS, apply this
transformation for height, opacity, and a transform which
skews the element and moves it to the left before setting
it to display: none */
.is-deleting {
opacity: 0;
height: 0;
display: none;
transform: skewX(50deg) translateX(-25vw);
}
ตอนนี้คุณมีทั้งสถานะ "เข้า" และ "ออก" สำหรับรายการในรายการสิ่งที่ต้องทําเหล่านี้แล้ว
การทำให้องค์ประกอบเคลื่อนไหวจากและไปยังเลเยอร์ด้านบน
หากต้องการทำให้องค์ประกอบเคลื่อนไหวจากเลเยอร์บนสุดและกลับ ให้ระบุ @starting-style
ในสถานะ "เปิด" เพื่อบอกเบราว์เซอร์ว่าให้เริ่มแสดงภาพเคลื่อนไหวจากจุดใด สำหรับกล่องโต้ตอบ สถานะการเปิดจะกำหนดด้วยแอตทริบิวต์ [open]
หากต้องการป๊อปอัป ให้ใช้คลาสจำลอง :popover-open
ตัวอย่างง่ายๆ ของกล่องโต้ตอบอาจมีลักษณะดังนี้
/* 0. IS-OPEN STATE */
dialog[open] {
translate: 0 0;
}
/* 1. BEFORE-OPEN STATE */
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
/* 2. EXIT STATE */
dialog {
transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
translate: 0 100vh;
}
ในตัวอย่างถัดไป เอฟเฟกต์ของช่วงอินพุตและเอาต์พุตจะแตกต่างกัน เข้าโดยแสดงภาพเคลื่อนไหวจากด้านล่างของวิวพอร์ตขึ้นด้านบน ออกโดยแสดงภาพเคลื่อนไหวจากด้านบนของวิวพอร์ตลงด้านล่าง และยังเขียนด้วย CSS ที่ฝังอยู่เพื่อให้มีภาพรวมที่ชัดเจนยิ่งขึ้น
เมื่อสร้างภาพเคลื่อนไหวของป๊อปอัป ให้ใช้คลาสจำลอง :popover-open
แทนแอตทริบิวต์ open
ที่ใช้ก่อนหน้านี้
.settings-popover {
&:popover-open {
/* 0. IS-OPEN STATE */
/* state when popover is open, BOTH:
what we're transitioning *in* to
and transitioning *out* from */
transform: translateY(0);
opacity: 1;
/* 1. BEFORE-OPEN STATE */
/* Initial state for what we're animating *in* from,
in this case: goes from lower (y + 20px) to center */
@starting-style {
transform: translateY(20px);
opacity: 0;
}
}
/* 2. EXIT STATE */
/* Initial state for what we're animating *out* to ,
in this case: goes from center to (y - 50px) higher */
transform: translateY(-50px);
opacity: 0;
/* Enumerate transitioning properties,
including display and allow-discrete mode */
transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}
ที่พัก overlay
แห่ง
สุดท้าย หากต้องการทำให้ popover
หรือ dialog
จากเลเยอร์ด้านบนจางหายไป ให้เพิ่มพร็อพเพอร์ตี้ overlay
ลงในรายการทรานซิชัน popover
และ dialog
จะหนีคลิปและการเปลี่ยนรูปแบบของบรรพบุรุษ รวมถึงวางเนื้อหาในเลเยอร์บนสุด หากไม่เปลี่ยน overlay
องค์ประกอบจะกลับไปเป็นแบบถูกตัด เปลี่ยนรูปแบบ และปกปิดทันที และคุณจะไม่เห็นการเปลี่ยน
[open] {
transition: opacity 1s, display 1s allow-discrete;
}
แต่ให้ใส่ overlay
ไว้ในทรานซิชันหรือภาพเคลื่อนไหวเพื่อทำให้ overlay
เคลื่อนไหวพร้อมกับฟีเจอร์อื่นๆ และตรวจสอบว่า overlay
อยู่ในเลเยอร์บนสุดเมื่อเคลื่อนไหว ซึ่งจะดูราบรื่นกว่ามาก
[open] {
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
นอกจากนี้ เมื่อคุณเปิดองค์ประกอบหลายรายการในเลเยอร์บนสุด การซ้อนทับจะช่วยให้คุณควบคุมการเปลี่ยนเลเยอร์บนสุดเข้าและออกได้อย่างราบรื่น คุณจะเห็นความแตกต่างในตัวอย่างง่ายๆ นี้ หากคุณไม่ได้ใช้ overlay
กับป๊อปอัปที่ 2 เมื่อเปลี่ยนออก ป๊อปอัปดังกล่าวจะออกจากเลเยอร์บนสุดก่อน โดยกระโดดไปอยู่หลังป๊อปอัปอีกรายการหนึ่ง จากนั้นจึงเริ่มการเปลี่ยน ผลลัพธ์ที่ได้จะไม่ราบรื่นมากนัก
หมายเหตุเกี่ยวกับการเปลี่ยนมุมมอง
หากคุณกำลังทำการเปลี่ยนแปลง DOM เช่น การเพิ่มและนำองค์ประกอบออกจาก DOM โซลูชันที่ยอดเยี่ยมอีกอย่างหนึ่งสำหรับภาพเคลื่อนไหวที่ราบรื่นคือการเปลี่ยนมุมมอง ตัวอย่างด้านบน 2 ตัวอย่างที่สร้างโดยใช้ทรานซิชันของมุมมองมีดังนี้
ในการสาธิตครั้งแรกนี้ แทนที่จะตั้งค่า @starting-style
และการแปลง CSS อื่นๆ การเปลี่ยนการแสดงผลจะจัดการการเปลี่ยนแปลงแทนการตั้งค่า การเปลี่ยนมุมมองมีการตั้งค่าดังนี้
ก่อนอื่น ให้กำหนด view-transition-name
ให้กับการ์ดแต่ละใบใน CSS
.card-1 {
view-transition-name: card-1;
}
.card-2 {
view-transition-name: card-2;
}
/* etc. */
จากนั้นใน JavaScript ให้รวมการเปลี่ยนรูปแบบ DOM (ในกรณีนี้คือการนำการ์ดออก) ไว้ในการเปลี่ยนมุมมอง
deleteBtn.addEventListener('click', () => {
// Check for browser support
if (document.startViewTransition) {
document.startViewTransition(() => {
// DOM mutation
card.remove();
});
}
// Alternative if no browser support
else {
card.remove();
}
})
ตอนนี้เบราว์เซอร์สามารถจัดการการค่อยๆ จางลงและมอร์ฟของการ์ดแต่ละใบไปยังตำแหน่งใหม่ได้แล้ว
อีกตัวอย่างหนึ่งที่มีประโยชน์คือการสาธิตการเพิ่ม/นำรายการออก ในกรณีนี้ โปรดอย่าลืมเพิ่ม view-transition-name
ที่ไม่ซ้ำกันสำหรับการ์ดแต่ละใบที่สร้าง
บทสรุป
ฟีเจอร์ใหม่เหล่านี้ของแพลตฟอร์มช่วยให้เราเข้าใกล้การสร้างภาพเคลื่อนไหวที่ราบรื่นเมื่อเข้าสู่และออกจากแพลตฟอร์มบนเว็บไปอีกขั้น ดูข้อมูลเพิ่มเติมได้จากลิงก์ต่อไปนี้