ฟีเจอร์ CSS ใหม่ 4 รายการสำหรับภาพเคลื่อนไหวเข้าและออกที่ราบรื่น

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

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

พร็อพเพอร์ตี้ transition-behavior จะระบุว่าจะเริ่มการเปลี่ยนภาพหรือไม่สําหรับพร็อพเพอร์ตี้แบบไม่ต่อเนื่อง โดยรับค่า 2 ค่า ได้แก่ normal และ allow-discrete โดยค่าเริ่มต้นคือ normal

  • normal: ระบบจะไม่เริ่มการเปลี่ยนสําหรับพร็อพเพอร์ตี้แบบไม่ต่อเนื่อง แต่จะสําหรับพร็อพเพอร์ตี้ที่อัตราส่วนได้เท่านั้น
  • allow-discrete: ระบบจะเริ่มการเปลี่ยนสำหรับพร็อพเพอร์ตี้แบบไม่ต่อเนื่องและพร็อพเพอร์ตี้ที่อัตราส่วนได้

หากต้องการเปิดใช้โหมด allow-discrete สำหรับพร็อพเพอร์ตี้ที่เฉพาะเจาะจง ให้ใส่พร็อพเพอร์ตี้นั้นไว้ในตัวย่อ transition ดังนี้

.card {   transition: opacity 0.25s, display 0.25s allow-discrete; /* Enable allow-discrete for the display property */ }  .card.fade-out {   opacity: 0;   display: none; } 
หมายเหตุ: การสาธิตทรานซิชันนี้แสดงเทคนิคที่แตกต่างจากการสาธิตภาพเคลื่อนไหวแรก แต่ดูคล้ายกัน

เมื่อเปลี่ยนพร็อพเพอร์ตี้แบบไม่ต่อเนื่องหลายรายการ คุณต้องตั้งค่า allow-discrete สำหรับพร็อพเพอร์ตี้การเปลี่ยนแต่ละรายการ เช่น

.card {   transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete; } 

หรือหากต้องการตั้งค่าลักษณะการทํางานของพร็อพเพอร์ตี้การเปลี่ยนทั้งหมด ให้ประกาศ transition-behavior: allow-discrete หลังการประกาศ transition ซึ่งมักเป็นวิธีที่ง่ายที่สุด

.card {   transition: opacity 0.5s, display 0.5s, overlay 0.5s;   transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */ } 

กฎ @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 ที่ไม่ซ้ำกันสำหรับการ์ดแต่ละใบที่สร้าง

บทสรุป

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