โมชัน
การเคลื่อนไหวมีหน้าที่ บอกลำดับ ตอบกลับการกระทำ หรือเชื่อมสองสถานะ ถ้าอธิบายเหตุผลในประโยคเดียวไม่ได้ ไม่ต้องขยับ
กฎสี่ข้อ
เส้นโค้งความเร่ง
สามเส้นต่อแบรนด์ ค่าเดียวกันใช้ได้ทั้งใน CSS transition และ GSAP CustomEase กดเล่นเพื่อดูความต่าง
ระยะเวลา 1.12 วินาที ช้ากว่า --dur-slow ให้เห็นรูปเส้นชัดขึ้น
0.16, 1, 0.3, 1เข้า เปิดเผย และตอบกลับ ใช้บ่อยที่สุด
0.76, 0, 0.24, 1ย้ายตำแหน่ง เปลี่ยนสถานะ และม่านเปลี่ยนหน้า
0.34, 1.56, 0.64, 1ผลตอบรับเล็กๆ เช่น ปุ่มกลมของสวิตช์ เด้งเกินเล็กน้อย
ระยะเวลา
.ds-switch__track::after {
transition: transform var(--dur-base) var(--ease-spring);
}
.ds-card[data-interactive]:hover {
transform: translateY(-3px);
transition: transform var(--dur-base) var(--ease-out);
}การเคลื่อนไหวที่ใช้ซ้ำ
การ์ดแรกเปลี่ยนตามแบรนด์ ที่เหลือใช้ได้ทั้งสองแบรนด์
ลายเซ็นของ ASWINOLOGY° วงกลมหมุนเข้ามา เติมสีไลม์ แล้วขยายเต็มพื้นที่ ใช้ครั้งเดียวต่อการเข้าเว็บ
เรียนทีละนิดเติบโตทีละองศา
บรรทัดเลื่อนขึ้นจากหลังหน้ากาก ใช้กับหัวข้อหลักของหน้าเท่านั้น
รายการเข้าทีละชิ้นห่างกัน 60 ms บอกว่าเป็นกลุ่มเดียวกัน ไม่เกินแปดชิ้นต่อครั้ง
ภาพหรือแผ่นสีเปิดจากซ้ายไปขวาด้วย clip-path ไม่ทำให้เลย์เอาต์ขยับ
สลับแบรนด์
ตัวสลับที่หัวเว็บใช้ View Transitions API วงกลมของแบรนด์ใหม่ขยายออกจากปุ่มที่กด สะท้อนประตูองศาของ ASWINOLOGY° เบราว์เซอร์ที่ไม่รองรับหรือผู้ใช้ที่ขอลดการเคลื่อนไหวจะสลับทันที
const transition = document.startViewTransition(() => {
document.documentElement.dataset.brand = next;
});
transition.ready.then(() => {
document.documentElement.animate(
{ clipPath: [`circle(0px at ${x}px ${y}px)`, `circle(${r}px at ${x}px ${y}px)`] },
{ duration: 720, easing: "cubic-bezier(0.76, 0, 0.24, 1)", pseudoElement: "::view-transition-new(root)" },
);
});สูตร GSAP ใน React
useGSAP ล้างแอนิเมชันให้เอง matchMedia จัดการผู้ใช้ที่ขอลดการเคลื่อนไหว
"use client";
import { useRef } from "react";
import { gsap } from "gsap";
import { useGSAP } from "@gsap/react";
gsap.registerPlugin(useGSAP);
export function Reveal({ children }: { children: React.ReactNode }) {
const scope = useRef<HTMLDivElement>(null);
useGSAP(() => {
const mm = gsap.matchMedia();
mm.add("(prefers-reduced-motion: no-preference)", () => {
gsap.fromTo("[data-reveal]",
{ autoAlpha: 0, y: 24 },
{ autoAlpha: 1, y: 0, duration: 0.9, ease: "power3.out", stagger: 0.08 });
});
return () => mm.revert(); // cleans up on unmount and on media change
}, { scope });
return <div ref={scope}>{children}</div>;
}ใช้เมื่อไร
ควรทำ
- ใช้ timeline เมื่อมีหลายขั้นตอน แทนการต่อ delay
- ใช้ autoAlpha แทน opacity เพื่อให้ซ่อนแล้วกดไม่ได้
- ใช้ ScrollTrigger กับหน้าเล่าเรื่องของ ASWINOLOGY° เท่านั้น
ไม่ควรทำ
- ฟัง scroll event เอง
- ผสม GSAP กับไลบรารีโมชันอื่นใน component เดียวกัน
- ใส่ marquee หรือแอนิเมชันวนไม่รู้จบเพื่อตกแต่ง