CSS
Transitions & Animations
transition
transition ทำให้การเปลี่ยนค่า CSS property เกิดขึ้นอย่างค่อยเป็นค่อยไป แทนที่จะเปลี่ยนทันทีทันใด — เป็นเครื่องมือพื้นฐานที่สุดในการสร้าง motion บน UI
หัวข้อนี้คืออะไร
transition คือ CSS property ที่ทำให้การเปลี่ยนค่าของ CSS property อื่น ๆ เกิดขึ้นอย่างนุ่มนวล (smooth) แทนที่จะเปลี่ยนทันทีทันใด สิ่งสำคัญที่ต้องเข้าใจตั้งแต่ต้น: transition ไม่ได้สร้างการเคลื่อนไหวขึ้นมาเอง — มันแค่ทำให้ "การเปลี่ยนค่า" ที่เกิดจากอะไรสักอย่าง (เช่น :hover) ดูนุ่มนวลขึ้น ถ้าไม่มีการเปลี่ยนค่าของ property → transition ก็จะไม่มีอะไรให้ทำงาน transition ประกอบด้วย 4 องค์ประกอบหลัก:
- transition-property — ระบุว่า property ไหนที่ต้องการให้ animate เช่น background-color, opacity, transform
- transition-duration — ระยะเวลาที่ใช้ในการเปลี่ยน เช่น 0.3s หรือ 300ms
- transition-timing-function — รูปแบบความเร็วในการเปลี่ยน เช่น ease, linear, ease-in-out
- transition-delay — หน่วงเวลาก่อนที่ transition จะเริ่มทำงาน เช่น 0.1s
ทดลองปรับ transition แบบเห็นผลทันที
ก่อนลงรายละเอียด ลองปรับค่า transition ทั้ง 4 ส่วนด้วยตัวเองก่อน: property คือสิ่งที่จะเปลี่ยน, duration คือเวลาที่ใช้, timing-function คือจังหวะความเร็ว, และ delay คือเวลารอก่อนเริ่ม
ทดลองปรับ transition
เลือก property แล้วปรับเวลา รูปแบบความเร็ว และ delay เพื่อดูว่า transition แต่ละส่วนส่งผลกับการเปลี่ยนสถานะอย่างไร
transition-property
Transform value
translateX(0px) -> translateX(180px)
Result
กล่องเลื่อนไปทางขวาชัดขึ้น
Total wait
delay 0ms + duration 600ms
transition-property: transform;
transition-duration: 600ms;
transition-timing-function: ease;
transition-delay: 0ms;ทำไมหัวข้อนี้สำคัญ
การเปลี่ยนแปลงที่เกิดขึ้นทันทีบน UI มักรู้สึก "กระทบ" หรือ "กระโดด" — ผู้ใช้ต้องการรู้สึกว่า interface ตอบสนองต่อพวกเขา ไม่ใช่แค่เปลี่ยนสถานะ transition ช่วยได้ใน 3 เรื่องหลัก: 1. Feedback — บอกผู้ใช้ว่า element ตอบสนองต่อ action ที่พวกเขากระทำ เช่น ปุ่มที่ค่อยๆ เปลี่ยนสีเมื่อ hover บอกว่า "คุณกำลังชี้อยู่ที่นี่" 2. Context — ช่วยให้ผู้ใช้ติดตามการเปลี่ยนแปลงได้ง่ายขึ้น ไม่ใช่แค่ "หายไปแล้วปรากฏใหม่" 3. ความรู้สึกมีคุณภาพ — UI ที่มี transition ที่ดีรู้สึก polish และตั้งใจออกแบบมา ต่างจาก UI ที่เปลี่ยนสถานะแบบหยาบ ข้อควรระวัง: transition ที่มากเกินไป หรือนานเกินไป ทำให้ UI ช้าและน่ารำคาญ ค่าที่เหมาะสมส่วนใหญ่อยู่ระหว่าง 150ms–400ms
ตัวอย่างจากชีวิตจริง
ลองนึกภาพ 2 สถานการณ์: ลิ้นชักแบบเปิดพรวด vs แบบเลื่อนออก ถ้าลิ้นชักเปิดพรวดออกมาทันที มันรู้สึก "สะดุด" และทำให้ตกใจเล็กน้อย แต่ถ้ามันค่อยๆ เลื่อนออกมา เราติดตามการเคลื่อนไหวได้ และรู้สึกเป็นธรรมชาติกว่ามาก ไฟสัญญาณจราจรที่เปลี่ยนสีทันทีทุกครั้ง มันยังทำงานได้ แต่เราจะสังเกตไหมถ้ามันค่อยๆ fade จากเขียวเป็นเหลือง? มันทำให้เราเตรียมตัวได้ดีกว่า บน UI จริง: ปุ่ม "สั่งซื้อ" — เมื่อ hover สีพื้นหลังค่อยๆ เข้มขึ้นในเวลา 0.2s บอกว่า "กดได้นะ" เมนู dropdown — ค่อยๆ ปรากฏขึ้นแทนที่จะโผล่ทันที ทำให้ดูไม่ตกใจ รูป thumbnail — เมื่อ hover ค่อยๆ สว่างขึ้นหรือขยาย บอกว่ากดได้
แนวคิดหลักที่ต้องเข้าใจ
องค์ประกอบทั้ง 4 ของ transition ทำงานอย่างไร: transition-property ระบุ property ที่ต้องการ animate ได้เป็น: ชื่อ property เฉพาะ เช่น background-color, opacity, transform หรือ all เพื่อ animate ทุก property ที่เปลี่ยน (แนะนำให้ระบุเฉพาะ property ที่ต้องการ ไม่ใช่ all) transition-duration ระยะเวลาของ transition หน่วยเป็น s (วินาที) หรือ ms (millisecond) ถ้าไม่ระบุ ค่าเริ่มต้นคือ 0s ซึ่งหมายความว่าไม่มี transition เกิดขึ้นเลย transition-timing-function ควบคุมความเร็วในแต่ละช่วงของ transition โดยทั่วไปใช้ ease (เริ่มช้า → เร็วกลาง → ช้าจบ) หรือ ease-in-out (เริ่มช้า → จบช้า) มากที่สุด transition-delay หน่วงเวลาก่อน transition เริ่มทำงาน ปกติไม่จำเป็น แต่มีประโยชน์เมื่อต้องการ sequence หลาย ๆ element
| Property | ค่าตัวอย่าง | ความหมาย |
|---|---|---|
| transition-property | background-color, opacity, all | property ที่ต้องการ animate |
| transition-duration | 0.3s, 300ms, 0.5s | ระยะเวลาของ transition |
| transition-timing-function | ease, linear, ease-in-out, ease-in, ease-out | รูปแบบความเร็ว |
| transition-delay | 0s, 0.1s, 200ms | หน่วงเวลาก่อนเริ่ม transition |
การทำงานทีละขั้นตอน
วิธีคิดเมื่อต้องการเพิ่ม transition ให้กับ element:
- 1. ถามว่า property ไหนที่จะเปลี่ยน — เช่น background-color เปลี่ยนเมื่อ hover ก็ระบุ transition-property: background-color
- 2. กำหนด duration ที่เหมาะสม — สำหรับ hover effect ทั่วไป 150ms–300ms เหมาะที่สุด ไม่ควรเกิน 500ms เพราะจะรู้สึกช้า
- 3. เลือก timing function — ease หรือ ease-in-out ใช้ได้กับเกือบทุกกรณี linear ใช้สำหรับ progress bar หรือ loading
- 4. เพิ่ม delay เฉพาะเมื่อจำเป็น — ส่วนใหญ่ไม่ต้องใช้ delay สำหรับ hover effect ธรรมดา
- 5. สำคัญมาก: วาง transition บน element ปกติ ไม่ใช่บน :hover — ถ้าวางบน :hover transition จะทำงานขาเข้าแต่จะหายทันทีเมื่อ mouse ออก
อ่านค่า transition-timing-function ให้ขาด
หลายคนเข้าใจผิดว่า timing-function ทำให้ transition "เร็วขึ้น" หรือ "ช้าลง" แต่จริง ๆ หน้าที่ของมันคือกำหนดว่าในช่วงต้น กลาง และท้ายของเวลาเดิมนั้น ความเร็วจะกระจายอย่างไร ถ้า duration เท่ากันหมด เช่น 0.6s เหมือนกันทุกตัว ความต่างจะอยู่ที่ "ความรู้สึก" ของการเคลื่อนที่: - บางค่าเริ่มช้าแล้วค่อยเร่ง - บางค่าเริ่มเร็วแล้วค่อยเบรก - บางค่าเร็วคงที่ตลอด ดังนั้นเวลาเลือก timing-function ให้ถามว่า motion นี้ควร "ออกตัว" และ "จบ" แบบไหน ไม่ใช่ถามแค่ว่าอยากให้มันเร็วหรือช้า
| Value | จังหวะที่รู้สึก | เหมาะกับงานแบบไหน |
|---|---|---|
| ease | เริ่มช้า เร็วขึ้นช่วงกลาง แล้วช้าลงก่อนจบ | ค่า default ที่ใช้ได้กับปุ่ม การ์ด และ UI ทั่วไป |
| linear | ความเร็วคงที่เท่ากันตลอด | progress bar, loader, movement ที่ไม่ควรมีช่วงเร่งหรือผ่อน |
| ease-in | เริ่มช้าแล้วค่อยเร่ง | element ที่เหมือนกำลังออกตัว เช่น card เริ่มลอย หรือ panel เริ่มเลื่อนเข้า |
| ease-out | เริ่มเร็วแล้วค่อยช้าลงก่อนหยุด | hover effect และ UI feedback ส่วนใหญ่ เพราะตอบสนองเร็วตั้งแต่ต้นและจบอย่างนุ่มนวล |
| ease-in-out | เริ่มช้า กลางเร็ว และจบช้า | motion ที่อยากให้ดูนุ่มทั้งตอนเริ่มและตอนจบ เช่น modal หรือ section reveal |
| cubic-bezier(...) | กำหนด curve เองได้ละเอียด | งานที่ต้อง fine-tune ความรู้สึกของ motion เกินกว่าค่า preset |
| steps(n, end) | ขยับเป็นจังหวะขั้น ๆ ไม่ลื่นต่อเนื่อง | sprite sheet, counter, หรือ effect ที่ตั้งใจให้กระโดดทีละ step |
- ถ้าอยากให้ผู้ใช้รู้สึกว่าระบบตอบสนองทันที ให้เริ่มลองจาก ease-out ก่อน เพราะมันออกตัวเร็ว
- ถ้า motion ควรดูนิ่งและเป็นธรรมชาติทั้งขาเข้าและขาออก ให้ใช้ ease-in-out
- ถ้าการเคลื่อนที่ควรเร็วคงที่ เช่น แถบโหลดหรือ element ที่เคลื่อนไปเรื่อย ๆ ให้ใช้ linear
- ถ้าค่า preset ยังไม่พอ ค่อยขยับไปใช้ cubic-bezier(...) เพื่อจูนจังหวะเอง
เริ่มจาก keyword value ก่อน แล้วค่อยใช้ cubic-bezier(...) หรือ steps(...) เมื่อมีเหตุผลชัดเจน
.btn-default { transition-timing-function: ease; }
.btn-hover { transition-timing-function: ease-out; }
.loader { transition-timing-function: linear; }
.modal { transition-timing-function: ease-in-out; }
.custom-curve { transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
.step-effect { transition-timing-function: steps(4, end); }ตัวอย่างเชิงเทคนิค — shorthand และ longhand
transition มี 2 รูปแบบการเขียน: longhand (แยก property) และ shorthand (รวมในบรรทัดเดียว) รูปแบบ shorthand: transition: property duration timing-function delay เช่น transition: background-color 0.3s ease หรือ transition: opacity 0.2s ease-in-out 0.1s ลองแก้โค้ด CSS แล้ว hover ที่ปุ่มและการ์ดเพื่อดูผล:
จุดที่ผู้เริ่มต้นมักสับสน
- วาง transition บน :hover แทนที่จะวางบน element → transition จะทำงานขาเข้า (เมื่อ hover) แต่จะหายทันทีเมื่อ mouse ออก เพราะ rule ที่มี transition ถูกลบออกด้วย
- ลืมระบุ transition-duration → ค่าเริ่มต้นคือ 0s ทำให้เหมือนไม่มี transition เลย ต้องระบุ duration เสมอ
- ใช้ transition: all → อาจทำให้ browser animate property ที่ไม่ต้องการ เช่น height, width ที่เปลี่ยนเมื่อ font โหลด ควรระบุ property ที่ต้องการเฉพาะเจาะจง
- transition ทำงานกับ property ที่มีค่าตัวเลข (numeric) เท่านั้น — เช่น opacity, color, transform, width ทำได้ แต่ display: none → block ทำไม่ได้เพราะไม่มีค่ากลาง
เปรียบเทียบ transition กับ animation
transition และ @keyframes animation ต่างกันอย่างไร:
| ลักษณะ | transition | @keyframes animation |
|---|---|---|
| วิธีทริกเกอร์ | ต้องมีการเปลี่ยนค่า เช่น :hover, :focus, class change | เริ่มอัตโนมัติหรือผ่าน animation-name |
| ทิศทาง | จาก A ไป B และกลับอัตโนมัติ | ตั้งค่า keyframe เองได้ เช่น 0% → 50% → 100% |
| ความซับซ้อน | เรียบง่าย เหมาะกับ state change | ซับซ้อนกว่า รองรับ sequence หลาย step |
| ทำซ้ำ | ไม่มี loop (เกิดตาม trigger) | กำหนด loop ได้ เช่น infinite |
| ใช้กับ | hover, focus, disabled, active states | loading spinner, pulse, slide-in จาก edge |
สรุปท้ายบทแบบจำง่าย
transition = "ทำให้การเปลี่ยนค่า CSS ดูนุ่มนวล" กฎสำคัญ 3 ข้อ:
- วาง transition บน element ปกติ ไม่ใช่บน :hover — มิฉะนั้น transition จะหายทันทีเมื่อ mouse ออก
- ระบุ duration เสมอ — ไม่มี duration = ไม่มี transition (ค่าเริ่มต้น 0s)
- ใช้ motion แบบพอดี — 150ms–300ms เหมาะสำหรับ hover effect ทั่วไป อย่าให้ช้าจนน่ารำคาญ
Lab 1 — เพิ่ม transition ให้ปุ่ม
โจทย์: ปุ่ม .btn ด้านล่างมี :hover ที่เปลี่ยน background-color แต่ยังไม่มี transition ทำให้สีเปลี่ยนทันที เพิ่ม transition: background-color 0.3s ease; ให้กับ .btn (ไม่ใช่บน :hover)
Lab 2 — ปรับ duration และ timing function
โจทย์: ปุ่มนี้มี transition แล้ว แต่ใช้ duration 0.05s (เร็วเกินไปจนแทบไม่เห็น) และ timing function เป็น linear แก้ให้ transition ดูเป็นธรรมชาติขึ้น: - เปลี่ยน duration เป็นอย่างน้อย 0.3s - เปลี่ยน timing function เป็น ease หรือ ease-in-out
Lab 3 — แก้ transition ที่วางผิดที่
โจทย์: การ์ด .card นี้มี transition แต่วางไว้ผิดที่ — วางบน .card:hover แทนที่จะวางบน .card ผลคือ transition จะทำงานขาเข้า (เมื่อ hover) แต่การ์ดจะกลับสู่สถานะปกติทันทีเมื่อ mouse ออก แก้โดย: ย้าย transition ไปวางบน .card แทน