Micro-interaction

Sun → Moon morph

Khi user nhấn nút đổi sáng/tối hoặc ⇧ + L, icon mặt trời xoay 360° và biến đổi sang mặt trăng trong 300ms ease-out — đủ nhanh để nhận thấy, đủ chậm để không gây giật.

📽️ 4 keyframe

0% · 0ms
Sun (start)
rotate(0) scale(1)
33% · 100ms
Rotating warm
rot(60°) sc(.85)
66% · 200ms
Rotating cool
rot(150°) sc(.95)
100% · 300ms
Moon (end)
rotate(360°) scale(1)

▶️ Live demo (hover nút bên dưới)

Hover hoặc click để xem hoạt cảnh
Trên thực tế chạy mỗi lần đổi giao diện · ưa thích bằng `prefers-reduced-motion` được tôn trọng

📐 CSS keyframes (đã định nghĩa trong styles.css)

@keyframes sun-moon-morph {
  0%   { transform: rotate(0deg)   scale(1);   opacity: 1;  filter: hue-rotate(0deg); }
  33%  { transform: rotate(60deg)  scale(.85); opacity: .8; filter: hue-rotate(40deg); }
  66%  { transform: rotate(150deg) scale(.95); opacity: .9; filter: hue-rotate(180deg); }
  100% { transform: rotate(360deg) scale(1);   opacity: 1;  filter: hue-rotate(220deg); }
}

.morph-demo { animation: sun-moon-morph 300ms ease-out forwards; }

/* Respects user motion preference */
@media (prefers-reduced-motion: reduce) {
  .morph-demo { animation: none; }
  /* Theme tokens swap immediately, icon swaps without rotation */
}

♿ Tiếp cận

prefers-reduced-motion
Khi user bật giảm chuyển động (system pref), animation bị tắt — chỉ swap icon, theme đổi tức thì.
Aria-pressed + label động
aria-label="Đổi sang giao diện tối" cập nhật theo trạng thái hiện tại.
Phím tắt ⇧L
Hoạt động trên toàn bộ ứng dụng · không xung đột với input fields (chỉ active khi không focus textbox).
Tôn trọng system theme
Lần đầu vào: theo prefers-color-scheme. Sau đó: ghi nhớ qua localStorage.