Kodokon kodokon.com

Transitions และ animations: @keyframes, transform, จังหวะเวลา

ทำ animation บน compositor ด้วย transform และ opacity จัดโครงสร้าง @keyframes ของคุณ และเคารพความชอบด้านการเคลื่อนไหวของผู้ใช้

10 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

ก่อนเลือกว่าจะ animate อะไร ให้ระลึกถึงไปป์ไลน์การเรนเดอร์: layout (เรขาคณิต), paint (พิกเซล), composite (การประกอบเลเยอร์บน GPU) การ animate width หรือ top จะกระตุ้น layout ในทุก ๆ เฟรม ตามด้วย paint บ่อยครั้ง นั่นคือสูตรของอาการกระตุก (jank) ที่ต่ำกว่า 60 fps ส่วน transform และ opacity ถูกจัดการโดย compositor โดยตรง โดยไม่ต้องย้อนกลับไปผ่านสองขั้นตอนแรก กฎแบบมืออาชีพ: animate เฉพาะสอง property นี้เมื่อทำได้ และจำลองส่วนที่เหลือ (translate แทน top, scale แทน width)

CSS
.button {
  transform: translateY(0);
  transition:
    transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1),
    opacity 0.15s ease-out;
}

.button:hover {
  transform: translateY(-2px);
}

.button:active {
  transform: translateY(0) scale(0.97);
}
Transition ที่เป็นมิตรกับ compositor พร้อมเส้นโค้งกำหนดเอง

เมื่อ transition ไม่เพียงพออีกต่อไป (มีขั้นตอนระหว่างกลาง, การวนซ้ำ, การเริ่มอัตโนมัติ) ให้ย้ายไปใช้ @keyframes การตั้งค่าสองอย่างสร้างความแตกต่างระหว่าง animation ที่สะอาดกับบั๊กทางภาพ: animation-fill-mode ควบคุมสถานะ ก่อน เริ่ม (backwards ใช้ keyframe แรกในระหว่างช่วงหน่วง) และ หลัง จบ (forwards แช่แข็ง keyframe สุดท้ายไว้) ส่วน both รวมทั้งสองอย่างเข้าด้วยกัน โปรดสังเกตด้วยว่า timing function ทำงาน ระหว่าง keyframe แต่ละคู่ ไม่ใช่ตลอดระยะเวลาทั้งหมด: คุณสามารถกำหนดมันใหม่ภายใน keyframe ได้

CSS
@keyframes slide-in {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  70% {
    transform: translateX(8px);
    opacity: 1;
  }
  to {
    transform: translateX(0);
  }
}

.toast {
  animation: slide-in 0.35s ease-out both;
}
การเข้ามาพร้อม overshoot เล็กน้อย

เครื่องมือเสริมสองอย่างที่ควรรู้ will-change: transform เลื่อนขั้นให้ element ไปอยู่บนเลเยอร์ของตัวเองก่อน animation เพื่อหลีกเลี่ยงการ raster ที่ล่าช้า แต่แต่ละเลเยอร์กินหน่วยความจำ GPU ดังนั้นจงใช้มันก่อน animation เพียงเล็กน้อยแล้วเอาออกหลังจากนั้น อย่าใช้เป็นสไตล์ถาวรบน element หลายสิบตัว ส่วน steps(n) แทนที่ interpolation แบบต่อเนื่องด้วยการกระโดดเป็นช่วง ๆ: จำเป็นสำหรับ sprite, เคอร์เซอร์แบบพิมพ์ดีด หรือนาฬิกา

CSS
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
การเคารพ prefers-reduced-motion

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. ทำไมจึงควรใช้ transform: translateX(100px) มากกว่า left: 100px สำหรับการเคลื่อนที่แบบ animate?
    • transform ได้รับการรองรับดีกว่าโดยเบราว์เซอร์รุ่นเก่า
    • transform ถูกจัดการโดย compositor โดยไม่ต้องคำนวณ layout ใหม่ในทุก ๆ เฟรม
    • left ทำงานเฉพาะกับ element ที่จัดตำแหน่งแบบ absolute เท่านั้น ส่วน transform ทำงานได้ทุกที่
    • transform รับค่าติดลบได้ ต่างจาก left
  2. animation-fill-mode: both ทำอะไร?
    • animation เล่นไปข้างหน้าแล้วเล่นย้อนกลับ
    • animation ถูกใช้กับ element และลูกหลานของมัน
    • สไตล์ของ keyframe แรกถูกใช้ในระหว่างช่วงหน่วง และสไตล์ของ keyframe สุดท้ายคงอยู่หลังจบ
  3. การใช้ will-change ที่ถูกต้องคืออะไร?
    • ใช้มันแบบทั่วทั้งหน้าบน * เพื่อเร่งความเร็วทั้งหน้า
    • เพิ่มมันก่อน animation ที่มีต้นทุนสูงเพียงเล็กน้อยแล้วเอาออกหลังจากนั้น
    • รวมมันเข้ากับ transform: translateZ(0) เสมอ
    • ใช้มันแทน transition สำหรับ micro-interaction