Bỏ qua tới nội dung

Nền tảng

Chuyển động

Đã đặc tả

Năm bậc thời lượng, bốn đường cong, sáu cặp presence, và một pressScale ở trên giá — không áp cho primitive nào. prefers-reduced-motion: reduce đưa mọi thời lượng về 0 và mọi presence về none. Có đúng một ngoại lệ trong cả kit: chỉ báo loading của Button.

Token

Thời lượng

TokenGiá trị
--nf-foundation-motion-duration-instantUnknown
--nf-foundation-motion-duration-fastUnknown
--nf-foundation-motion-duration-standardUnknown
--nf-foundation-motion-duration-deliberateUnknown
--nf-foundation-motion-duration-extendedUnknown

Thang dừng ở 320ms: trên đó, một chuyển động chuyển từ "phản hồi" sang "chờ", và thứ cần sửa là chuyển động đó, không phải thêm một bậc.

Dialog: deliberate 240ms so với extended 320ms. Clause 15 của DS-014 rút --nf-motion-dialog-in từ extended (320ms) xuống deliberate (240ms) — bản bên trái đang ship hôm nay. Lập luận là số học về đường cong: easing-enter là cubic-bezier(0.16, 1, 0.3, 1), đạt phần lớn quãng đường trong khoảng một phần ba đầu, nên ở 320ms đoạn cuối gần như không còn chuyển động nhìn thấy được. Nhưng phán quyết cuối là thẩm mỹ, không phải số học, và thuộc chủ sở hữu — đây là thứ phải nhìn mới quyết được, nên hai bản chạy cạnh nhau dưới đây, giống hệt mọi mặt trừ thời lượng vào.

Đang ship — deliberate, 240ms

Giá trị thật của --nf-motion-dialog-in sau clause 15 của DS-014.

Bản cũ để so — extended, 320ms

Specimen của trang tài liệu: keyframe nf-dialog-in ghép tay với easing-enter và duration-extended, không phải một token composite nào tiêu thụ.

Token

Đường cong

TokenGiá trị
--nf-foundation-motion-easing-standardUnknown
--nf-foundation-motion-easing-exitUnknown
--nf-foundation-motion-easing-enterUnknown
--nf-foundation-motion-easing-exit-snappyUnknown

Vào và ra không đối xứng, và đó là cố ý: thứ đang đến chậm dần để mắt bắt được chỗ nó dừng; thứ đang đi nhanh dần để ra khỏi đường nhìn.

Token

pressScale — một token trên giá

DS-018 clause 2 đảo DS-014 clause 16. Câu cũ — "áp cho mọi thứ nhấn được… một luật, không ngoại lệ" — không còn hiệu lực. --nf-foundation-motion-press-scale vẫn là 0.98 và vẫn ở trong corpus token. Nó không được áp cho bất kỳ primitive nào, và chỉ được áp khi chủ sở hữu yêu cầu cho một bề mặt cụ thể. infra/check-control-states.mjs chặn chuỗi press-scale xuất hiện trong packages/ui/src/**.

Vì sao. Ở chiều cao mặc định 36px sau DS-017 clause 3, một phép thu 2% dịch 0,7 pixel — dưới ngưỡng đọc được thành phản hồi, nhưng đủ để trình duyệt lấy mẫu lại chữ trong nhãn và làm nó rung.

Cảnh báo

Trạng thái control không còn thuộc trang này. Hover, pressed, focus và selected nay kể bằng màu bề mặt và ring, và chúng sống ở /foundations/states — A33 cấm kể trạng thái bằng hình học. Ranh giới sau DS-018: trạng thái là control đang được tương tác và không có chuyển động; presence là bề mặt đang xuất hiện hay biến mất, và đó là thứ trang này sở hữu.

Bậc fast 120ms vẫn dùng cho chuyển tiếp màu của trạng thái — dòng fast ở bảng thời lượng phía trên vẫn đúng. Cái biến mất là chuyển động hình học, không phải chuyển tiếp.

Render

Presence — sáu cặp, chạy được

Mười hai token --nf-motion-*, sáu cặp vào / ra. Mỗi ô dưới đây chạy đúng chuyển động -in của cặp đó; bấm "Chạy lại" để xem lại.

overlay

Mờ vào và mờ ra. Không di chuyển

menu

Phóng từ overlay-scale. Ra bằng exit-snappy

popover

Mờ vào, phóng từ overlay-scale, cộng dịch chuyển 4px ngược chiều data-side

dialog

Nghỉ ở giữa màn hình, vào bằng deliberate và enter

sheet

Đi theo trục Y vào hộp nghỉ của nó, sát cạnh

toast

Neo đáy. Vào và ra theo DS-008

Trợ năng

Reduced motion

Khối @media (prefers-reduced-motion: reduce) đặt cả năm duration về 0ms và cả mười hai token presence về none. Khối đó không chạm easing và không chạm pressScale: easing giữ nguyên vì với thời lượng 0 đường cong không còn tác dụng, và pressScale giữ nguyên vì nó không phải chuyển động theo thời gian — nó là một trạng thái tĩnh trong lúc ngón tay còn đè.

Cảnh báo

Ngoại lệ duy nhất của cả kit: --nf-component-button-loading-duration dài ra thành -loading-duration-reduced thay vì về 0ms. Một vòng quay đứng yên đọc như một control bị hỏng, không như bình tĩnh. Không có ngoại lệ thứ hai.

Nghĩa vụ

Obligation

IDObligationWCAG 2.2
A13Reduced motion2.3.3 (AAA, kit vẫn theo)
A14Không chớp2.3.1 Three Flashes (A)
A15Một hệ chuyển động— (luật nội bộ)

A13

A13 Reduced motion

Dưới prefers-reduced-motion: reduce, mọi transition-duration và animation-duration về instant. Trạng thái cuối vẫn phải đúng — tắt chuyển động không được làm mất trạng thái. Ngoại lệ duy nhất là chỉ báo loading của Button, và nó dài ra chứ không dừng, vì một vòng quay đứng yên truyền đạt "đã treo".

Kiểm. Bật giảm chuyển động ở cấp hệ điều hành, hoặc emulate trong devtools. Mở dialog: nó xuất hiện ngay, đúng vị trí. Bấm một nút loading: chỉ báo vẫn quay, chậm hơn.

A14

A14 Không chớp

Không nội dung nào nhấp nháy quá ba lần trong một giây. WCAG 2.3.1 là tiêu chí mức A và liên quan tới nguy cơ co giật — đây không phải chuyện thẩm mỹ. Lỗi được báo bằng chữ, màu và biểu tượng, không bằng nhấp nháy.

Kiểm. Không có @keyframes nào trong corpus có chu kỳ dưới 333ms đi kèm thay đổi độ sáng lớn.

A15

A15 Một hệ chuyển động

Kit đã có hệ chuyển động. Không thêm Framer Motion, GSAP, react-spring, hay CSS animation viết tay cho việc mà token đã làm được — hai hệ chuyển động nghĩa là hai nơi phải nhớ tắt khi reduced-motion bật, và một trong hai sẽ bị quên.

Kiểm. package.json của mọi app không có phụ thuộc animation. Mọi animation trong mã đọc var(--nf-motion-*).

Token

Alias component

TokenTrỏ về
--nf-component-transition-durationfast
--nf-component-transition-easingstandard
--nf-component-overlay-scalethang phóng của menu và dialog
--nf-component-button-loading-durationthời lượng vòng loading; dài ra ở reduced motion
--nf-component-button-loading-duration-reducedgiá trị dài dùng ở reduced motion

Quy tắc

Do / Don't

DoDon'tVì sao
Dùng một cặp presence có sẵnGhép duration với easing để tự dựng animationHai dialog tự ghép sẽ vào khác nhau
Dùng fast cho hover và pressedDùng standard cho hover180ms trên hover làm con trỏ có cảm giác dính
Dùng extended cho thứ chặn người dùngDùng extended cho một tooltipTooltip chậm đọc như trang bị treo
Để reduced motion về 0Thêm một hệ chuyển động thứ hai để "vẫn có gì đó"A15: một hệ chuyển động
Đọc --nf-component-transition-* từ primitiveGõ 120msMột ms trần không theo reduced motion

Chưa quyết

Open questions

QuestionOwnerResolves when
Có cặp presence thứ sáu cho popover không, hay popover dùng menu?—Đóng 2026-09-24 theo DS-014 clause 14. Cặp thứ sáu của riêng nó
pressScale có nên tắt ở reduced motion không?nexoboxvn@gmail.comCó phản hồi từ người dùng thật
Có cần token cho độ trễ, ví dụ độ trễ hiện tooltip?nexoboxvn@gmail.comTooltip trở thành một primitive trong catalogue