Skill: scroll-effects
Hub hiệu ứng cuộn trang:
64 bản gốc nguyên văn (freefrontend/CodePen, MIT) ở
— duyệt gallery, copy nguyên file. Kèm 7 hiệu ứng vanilla tự viết trong
cho dự án không được kéo lib ngoài.
WHAT
Purpose và context
- Purpose: gắn hiệu ứng cuộn trang nhẹ vào trang đích — mặc định copy nguyên file bản GỐC từ ; dự án không được kéo lib ngoài thì dùng 7 pattern vanilla trong .
- Trigger (when to use):
- Trang cần hiệu ứng hiện-dần khi cuộn, chữ stagger, highlight dẫn mắt, nav co lại, nút về đầu trang, mục lục bám theo section, hoặc parallax nhẹ.
- User nói "hiệu ứng scroll", "scroll to top", "scrollspy", "parallax", "reveal khi cuộn".
- Non-goals: KHÔNG dùng cho: chuyển ảnh điện ảnh nặng GPU (đó là ), trục timeline mốc thời gian (đó là ), cuộn ngang pin-section kiểu GSAP ScrollTrigger phức tạp (vượt phạm vi skill nhẹ này — nói rõ với user).
Mental model
nhu cầu hiệu ứng → gallery 64 bản gốc (mặc định, copy nguyên file) hoặc 7 pattern vanilla (không được kéo lib) → adapt token theo design.md → một IntersectionObserver + một scroll listener rAF → reduced-motion tắt hết → verify playwright
. Hub rẽ sang skill con tương ứng khi mục gallery thuộc skill con.
Input và output contract
| Field | Required? | Ý nghĩa |
|---|
| In | hiệu ứng cần | có | một trong 7 pattern hoặc mục gallery |
| In | ràng buộc dự án | không | có được kéo lib/file ngoài không; có không |
| Out | file hiệu ứng trong dự án | có | bản gốc copy nguyên (giữ comment ghi công dòng đầu) hoặc asset vanilla đã adapt |
| Out | bằng chứng verify | có | ảnh trước/sau cuộn, xuất hiện, không horizontal overflow |
Rules và capabilities
- RULE-01 (MUST):
prefers-reduced-motion: reduce
→ tắt toàn bộ: CSS ép hiện ngay không transition, JS bỏ smooth scroll và parallax (đã code sẵn trong assets, đừng xoá nhánh này khi adapt).
- RULE-02 (MUST): Một dùng chung cho reveal + stagger + highlight + TOC (đã gộp trong ) — đừng tạo 4 observer riêng.
- RULE-03 (MUST): Scroll listener duy nhất, rAF-throttle — nav + top + parallax đọc chung một mỗi frame, không gắn 3 listener rời.
- RULE-04 (MUST): Verify bằng : chụp trước/sau cuộn, assert xuất hiện, đo không có horizontal overflow do parallax.
- RULE-05 (MUST): Khi adapt vào dự án có : đổi token màu/spacing, giữ nguyên tên (JS bám vào chúng).
- Capabilities: đọc gallery/repo asset ngoài (mạng) hoặc asset nội bộ; ghi file front-end dự án; chạy trình duyệt headless qua HTTP local.
Failure boundaries
- Yêu cầu là WebGL nặng, timeline mốc, hoặc pin-section GSAP phức tạp → blocked ngoài phạm vi, nói rõ với user và chỉ skill đúng.
- Không truy cập được gallery/repo ngoài hoặc dự án cấm lib ngoài → dùng 7 pattern vanilla (không phải lỗi).
- Verify playwright không thấy hoặc có horizontal overflow → failed, sửa rồi verify lại.
HOW
Main workflow
| Step | Type | Inputs | Action | Outputs/exit | Failure/next |
|---|
| W01 | judgment | yêu cầu | Khớp phạm vi (không phải blur/timeline/GSAP pin) | hiệu ứng trong phạm vi | ngoài phạm vi → blocked |
| W02 | judgment | ràng buộc dự án | Chọn nguồn: bản gốc gallery (mặc định) hay vanilla (B01) | nguồn | — |
| W03 | effect | nguồn | Bản gốc: mở link chạy → copy nguyên (+ ) → giữ comment ghi công → chỉ sửa nội dung/ảnh/màu | file trong dự án | — |
| W04 | effect | | Adapt token màu/spacing, giữ , giữ nhánh reduced-motion | file đã adapt | — |
| W05 | deterministic | trang qua HTTP | : chụp trước/sau cuộn, assert , đo overflow | PASS | FAIL → sửa, lặp W05 |
Chi tiết từng bước (nguồn chân lý cho W01–W05):
Bản gốc — dùng TRƯỚC (copy nguyên file, đừng viết lại)
Code gốc NGUYÊN VĂN của tác giả (CodePen public = MIT) nằm ở repo ngoài
— gallery chạy thật:
https://rheinmir.github.io/uiux-asset/scroll-effects/ .
Quy trình: mở link
chạy để xem đúng hiệu ứng → copy nguyên file
(+ thư mục
nếu file trỏ tới) vào dự án → giữ comment ghi công dòng đầu → chỉ sửa nội dung/ảnh/màu. Chạy local qua HTTP, không
.
git clone --depth 1 https://github.com/Rheinmir/uiux-asset
nếu cần cả bộ offline.
Hub: duyệt cả 64 mục ở gallery (lọc theo tên/kỹ thuật/tác giả), rồi rẽ sang skill con tương ứng.
trong skill này chỉ là bản rút gọn vanilla tự viết — dùng khi dự án KHÔNG được kéo lib ngoài; mặc định dùng bản gốc ở trên.
Assets
(trang demo ráp sẵn cả 7) +
assets/scroll-effects.css
+
— đọc rồi ADAPT (đổi class/token theo
của dự án nếu có).
Branches
| ID | Kind | Guard | Hành vi | Skip / failure | Rejoin |
|---|
| B01 | conditional_required | dự án KHÔNG được kéo lib/file ngoài | dùng 7 pattern vanilla trong (mục Reference bên dưới) thay bản gốc | được kéo ngoài → bản gốc gallery | W04 |
| B02 | user_optional | cần cả bộ gốc offline | repo | — | W03 |
| B03 | conditional_required | mục gallery thuộc một skill con | rẽ sang skill con tương ứng | — | kết thúc ở skill con |
Validation và stopping
Chạy qua HTTP local (không
). PASS khi playwright chụp trước/sau cuộn thấy
, không horizontal overflow, và với reduced-motion mọi phần tử hiện ngay. Dừng khi PASS; FAIL thì sửa và verify lại.
Examples
- Positive: "thêm scroll to top + scrollspy cho trang docs, không được kéo lib" → B01 dùng + từ , đổi token theo , giữ → playwright: nút hiện khi , link TOC nhận .
- Boundary/failure: "làm section cuộn ngang pin kiểu GSAP" → ngoài phạm vi skill nhẹ này → nói rõ với user, không cố dựng bằng parallax .
Reference — 7 pattern (markup tối thiểu + cơ chế)
1. Reveal on scroll —
Phần tử mờ + trượt nhẹ, hiện khi cuộn vào khung nhìn.
html
<div data-se-reveal>Lộ dần khi cuộn tới</div>
gắn
→ CSS transition
. Tham khảo gallery scroll-effects #9 (Animated Scroll Highlight Annotations) về
trường hợp dùng, không dùng code của họ.
2. Staggered text —
Các dòng chữ hiện nối tiếp nhau.
html
<h2 data-se-stagger>
<span>Dòng một</span><span>Dòng hai</span><span>Dòng ba</span>
</h2>
JS gán
cho mỗi
→ CSS
transition-delay: calc(var(--i) * 90ms)
. Chỉ tách theo phần tử con có sẵn, không tự split text node (giữ DOM đơn giản, tránh lỗi a11y).
3. Scroll highlight — [data-se-highlight] > mark
Đánh dấu ý chính, vệt màu quét trái→phải khi đoạn văn vào khung nhìn.
html
<p data-se-highlight>Đọc tới đây <mark>ý chính hiện ra</mark> rồi đọc tiếp.</p>
dùng
background-size: 0% → 100%
transition khi cha có
. Dùng
ngữ nghĩa thật, không span giả.
4. Sticky shrink nav —
Header co gọn khi cuộn xuống, phồng lại khi về đầu.
html
<header data-se-nav class="site-nav">…</header>
Scroll listener (rAF-throttle) toggle
khi
. Chỉ đổi padding/font-size qua class, không set style inline từng frame.
5. Scroll to top —
Nút về đầu trang, chỉ hiện sau khi cuộn qua một màn hình.
html
<button data-se-top aria-label="Về đầu trang">↑</button>
Click →
window.scrollTo({ top: 0, behavior: "smooth" })
(trừ khi
→
). Ngưỡng hiện:
.
6. Scrollspy TOC — [data-se-toc] a[href^="#"]
+
Mục lục sticky, link sáng theo section đang đọc.
html
<nav data-se-toc><a href="#s1">Mục 1</a><a href="#s2">Mục 2</a></nav>
<section id="s1">…</section><section id="s2">…</section>
với
rootMargin: "-40% 0px -55% 0px"
→ link khớp nhận
. Tham khảo gallery #19 (Auto-Generated Anchor TOC) về
ý tưởng, code tự viết.
7. Parallax nhẹ —
Lớp nội dung trôi chậm hơn/nhanh hơn tốc độ cuộn.
html
<div data-se-parallax="0.15">Trôi chậm tạo chiều sâu</div>
rAF loop:
translateY = (elCenter - viewportCenter) * speed
. Giá trị
khuyến nghị
; vượt quá gây say chuyển động. KHÔNG dùng cho chữ nhỏ cần đọc chính xác.
Origin
- User chốt "làm đi hỏi nhiều quá" → thay vì bulk-copy 81 tác phẩm, viết BỘ GỐC 7 pattern generic (kỹ thuật chuẩn ngành: IntersectionObserver/scroll listener/rAF — không phải biểu đạt sáng tạo riêng của ai) để downstream tham khảo code mẫu ngay, đúng cách / đã làm.