use-scroll-animate 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +113 -58
- package/LICENSE +21 -21
- package/README.md +217 -214
- package/README_ja.md +106 -69
- package/README_zh.md +106 -69
- package/dist/index.d.mts +302 -0
- package/dist/index.d.ts +302 -0
- package/dist/index.esm.js +1179 -697
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1193 -708
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1179 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +13 -14
- package/dist/index.umd.js.map +1 -1
- package/dist/types/core.d.ts +41 -7
- package/dist/types/index.d.ts +36 -33
- package/dist/types/presets.d.ts +15 -15
- package/dist/types/react.d.ts +29 -18
- package/dist/types/sequence.d.ts +38 -0
- package/dist/types/stagger.d.ts +25 -0
- package/dist/types/types.d.ts +139 -123
- package/dist/types/vue.d.ts +28 -18
- package/package.json +81 -35
- package/CONTRIBUTING.md +0 -76
- package/examples/react/App.tsx +0 -61
- package/examples/vanilla/index.html +0 -201
- package/rollup.config.js +0 -41
- package/src/core.ts +0 -373
- package/src/index.ts +0 -48
- package/src/presets.ts +0 -148
- package/src/react.ts +0 -175
- package/src/types.ts +0 -161
- package/src/vue.ts +0 -118
- package/tsconfig.json +0 -17
package/README.md
CHANGED
|
@@ -1,214 +1,217 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
# use-scroll-animate 🚀
|
|
4
|
-
|
|
5
|
-
**A lightweight (~
|
|
6
|
-
|
|
7
|
-
[](https://github.com/HarrisonCN/use-scroll-animate/releases)
|
|
8
|
-
[](https://github.com/HarrisonCN/use-scroll-animate)
|
|
9
|
-
[](https://opensource.org/licenses/MIT)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
```
|
|
62
|
-
import {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
##
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
|
132
|
-
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
animation:
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# use-scroll-animate 🚀
|
|
4
|
+
|
|
5
|
+
**A lightweight (~5KB gzipped), dependency-free scroll animation library for the modern web.**
|
|
6
|
+
|
|
7
|
+
[](https://github.com/HarrisonCN/use-scroll-animate/releases)
|
|
8
|
+
[](https://github.com/HarrisonCN/use-scroll-animate)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
|
|
11
|
+
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
## Why `use-scroll-animate`?
|
|
16
|
+
|
|
17
|
+
In 2025, performance is everything. Traditional scroll animation libraries often bundle heavy dependencies, rely on outdated scroll event listeners, or force you into a specific framework.
|
|
18
|
+
|
|
19
|
+
`use-scroll-animate` is built differently:
|
|
20
|
+
- ⚡ **Zero Dependencies**: Pure Vanilla JS/TypeScript.
|
|
21
|
+
- 🚀 **High Performance**: Powered by `IntersectionObserver` and the native `Web Animations API`. No scroll event listeners by default (the opt-in scroll-progress mode uses a single passive, rAF-throttled listener, only while tracked elements are on screen).
|
|
22
|
+
- 🪶 **Ultra Lightweight**: ~4.8KB gzipped for the core (tree-shaken, minified ESM); everything incl. `sequence`, `staggerChildren` and the React/Vue helpers is ~6.1KB (UMD ~6.2KB).
|
|
23
|
+
- 🧩 **Framework Agnostic**: Works seamlessly with Vanilla JS, React, Vue, Svelte, and more. First-class React Hooks and Vue Composables included.
|
|
24
|
+
- ♿ **Accessible**: Respects `prefers-reduced-motion` out of the box (content is shown immediately, no entrance or parallax motion).
|
|
25
|
+
- 🖥️ **SSR-safe**: Importing (and even calling) the API on the server is a no-op.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install use-scroll-animate
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## v1.4.0 New Features ✨
|
|
34
|
+
|
|
35
|
+
### True scroll progress (`progressMode: 'scroll'`)
|
|
36
|
+
By default `onProgress` reports the element's *visible ratio*, which never reaches 1 for elements taller than the screen. Opt in to real scroll progress: `0` when the element's top reaches the bottom of the viewport, `1` when its bottom leaves the top.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
ScrollAnimate.observe('.chapter', {
|
|
40
|
+
progressMode: 'scroll',
|
|
41
|
+
onProgress: (el, p) => el.style.setProperty('--progress', p),
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Parallax uses the same progress, so `progressMode: 'scroll'` also gives smooth parallax on tall sections. HTML: `data-sa-progress="scroll"`. Also exported as a helper: `getScrollProgress(el, root?)`.
|
|
46
|
+
|
|
47
|
+
### Stagger dynamically added children
|
|
48
|
+
`staggerChildren()` (vanilla), `useScrollStagger()` (React **and now Vue**) accept `observeChildren: true`. A `MutationObserver` picks up children added later (infinite lists, "load more"): those added before the reveal join the stagger; those added after it animate when they scroll into view, staggered per batch.
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import { staggerChildren } from 'use-scroll-animate';
|
|
52
|
+
const stop = staggerChildren(document.querySelector('#feed'), {
|
|
53
|
+
animation: 'fade-in-up', stagger: 60, observeChildren: true,
|
|
54
|
+
});
|
|
55
|
+
// later: stop();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Timelines with `sequence()`
|
|
59
|
+
Chain animations across elements. Each step starts when the previous one ends; `gap` adds a pause (negative values overlap) and `at` sets an absolute start time.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { sequence } from 'use-scroll-animate';
|
|
63
|
+
|
|
64
|
+
const tl = sequence([
|
|
65
|
+
{ target: '.hero h1', animation: 'fade-in-up', duration: 700 },
|
|
66
|
+
{ target: '.hero p', animation: 'blur-in', gap: -300 },
|
|
67
|
+
{ target: '.hero .btn', animation: 'scale-up', stagger: 80 },
|
|
68
|
+
], { trigger: '.hero', easing: 'soft-spring' }); // auto-plays once when .hero enters
|
|
69
|
+
|
|
70
|
+
await tl.play(); // or play manually; resolves when every step is done
|
|
71
|
+
tl.cancel(); // stop and leave everything visible
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### New presets
|
|
75
|
+
`scale-up`, `blur-in-up`, `flip-up`, `flip-down`, `rotate-left`, `rotate-right`, and clip-path reveals `clip-up`, `clip-down`, `clip-left`, `clip-right`, `clip-circle`.
|
|
76
|
+
|
|
77
|
+
### Smaller memory footprint
|
|
78
|
+
Finished `once` elements are dropped from the registry right after they animate (unless they still need parallax/`onProgress`), so long pages and SPAs don't keep thousands of records alive. They're remembered in a `WeakSet`, so `init()`/`observe()` never replay them. Set `createScrollAnimate({ autoUnregister: false })` to keep them listed in `getObservedElements()` as before.
|
|
79
|
+
|
|
80
|
+
### Proper `exports` map
|
|
81
|
+
Node ESM (`import`) resolves to `dist/index.mjs`, CommonJS (`require`) to `dist/index.js`, each with matching bundled types. The legacy `main`/`module`/`unpkg` fields and `dist/*` deep imports keep working.
|
|
82
|
+
|
|
83
|
+
## v1.3.0: Custom Easing 🎨
|
|
84
|
+
|
|
85
|
+
You can now use custom cubic-bezier curves or even JavaScript functions to create complex physical effects.
|
|
86
|
+
|
|
87
|
+
### 1. Cubic-Bezier Array
|
|
88
|
+
Pass an array of 4 numbers to define a custom cubic-bezier curve.
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
ScrollAnimate.observe('.box', {
|
|
92
|
+
animation: 'fade-in-up',
|
|
93
|
+
easing: [0.68, -0.55, 0.265, 1.55] // Custom bounce effect
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 2. Custom Easing Function
|
|
98
|
+
Pass a function `(t: number) => number` for complete control over the animation timing.
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
ScrollAnimate.observe('.box', {
|
|
102
|
+
easing: (t) => t * t * (3 - 2 * t) // Custom smooth-step
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 3. New Physics Presets
|
|
107
|
+
We've added high-quality physics-based easing presets:
|
|
108
|
+
- `spring`: Standard spring effect.
|
|
109
|
+
- `soft-spring`: Gentle, bouncy entrance.
|
|
110
|
+
- `heavy-bounce`: Dramatic bounce effect.
|
|
111
|
+
|
|
112
|
+
## Quick Start (Vanilla JS / HTML)
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<div data-sa data-sa-animation="fade-in-up" data-sa-easing="soft-spring">
|
|
116
|
+
I have a soft spring effect!
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<div data-sa data-sa-animation="zoom-in" data-sa-easing="[0.34, 1.56, 0.64, 1]">
|
|
120
|
+
I use a custom cubic-bezier array!
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<script type="module">
|
|
124
|
+
import ScrollAnimate from 'use-scroll-animate';
|
|
125
|
+
ScrollAnimate.init();
|
|
126
|
+
</script>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Options
|
|
130
|
+
|
|
131
|
+
| Option | Type | Default | Description |
|
|
132
|
+
|--------|------|---------|-------------|
|
|
133
|
+
| `animation` | `string` \| `string[]` \| `{ from, to }` | `'fade-in-up'` | Preset name, array of presets to combine, or custom keyframes |
|
|
134
|
+
| `duration` | `number` | `600` | Duration in ms |
|
|
135
|
+
| `delay` | `number` | `0` | Delay in ms |
|
|
136
|
+
| `easing` | `string` \| `number[]` \| `function` | `'ease'` | CSS easing, preset (`spring`, `soft-spring`, `heavy-bounce`), cubic-bezier array, or `(t) => number` |
|
|
137
|
+
| `threshold` | `number` \| `number[]` | `0.1` | IntersectionObserver threshold(s) |
|
|
138
|
+
| `rootMargin` | `string` | `'0px'` | IntersectionObserver root margin |
|
|
139
|
+
| `once` | `boolean` | `true` | Animate only the first time the element enters |
|
|
140
|
+
| `repeat` | `boolean` | `false` | Re-hide on leave and replay on every entry |
|
|
141
|
+
| `offset` | `number` | `0` | Trigger the animation this many px after the element enters the viewport |
|
|
142
|
+
| `stagger` | `number` | `0` | Extra delay (ms) per sibling revealed in the same batch |
|
|
143
|
+
| `parallax` | `{ x, y, rotate, scale, speed }` | `{}` | Scroll-driven parallax (keeps running after the entrance animation) |
|
|
144
|
+
| `onStart` / `onComplete` / `onEnter` / `onLeave` | `(el) => void` | – | Lifecycle callbacks |
|
|
145
|
+
| `onProgress` | `(el, progress) => void` | – | Progress (0–1) as the element scrolls — visible ratio, or true scroll progress with `progressMode: 'scroll'` |
|
|
146
|
+
| `progressMode` | `'ratio'` \| `'scroll'` | `'ratio'` | How `onProgress`/parallax progress is measured (`'scroll'`: 0 = top enters at the bottom, 1 = bottom leaves at the top) |
|
|
147
|
+
|
|
148
|
+
Every option is also available as a data attribute: `data-sa-animation`, `data-sa-duration`, `data-sa-delay`, `data-sa-easing`, `data-sa-threshold`, `data-sa-root-margin`, `data-sa-once`, `data-sa-repeat`, `data-sa-offset`, `data-sa-stagger`, `data-sa-progress`, `data-sa-parallax-x|y|rotate|scale|speed`.
|
|
149
|
+
|
|
150
|
+
**Presets:** `fade-in`, `fade-in-up|down|left|right`, `zoom-in`, `zoom-out`, `scale-up`, `flip-x`, `flip-y`, `flip-up`, `flip-down`, `slide-up|down|left|right`, `bounce`, `rotate-in`, `rotate-left`, `rotate-right`, `blur-in`, `blur-in-up`, `skew-in`, `scale-x`, `scale-y`, `clip-up|down|left|right`, `clip-circle`, `shimmer`, `pulse`, `swing`. Combine them with an array, e.g. `['fade-in', 'clip-up']`.
|
|
151
|
+
|
|
152
|
+
**Global config** (`createScrollAnimate(config)` / `configure()`): `defaultAnimation`, `defaultDuration`, `defaultDelay`, `defaultEasing`, `defaultThreshold`, `defaultRootMargin`, `defaultRepeat`, `defaultOnce`, `defaultOffset`, `hiddenClass`, `visibleClass`, `useClassNames`, `disabled`, `root`, `autoUnregister` (default `true`).
|
|
153
|
+
|
|
154
|
+
## Instance API
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
import ScrollAnimate, { createScrollAnimate } from 'use-scroll-animate';
|
|
158
|
+
|
|
159
|
+
ScrollAnimate.init(root?); // observe every [data-sa] element (safe to call again after DOM changes)
|
|
160
|
+
ScrollAnimate.observe(target, opts); // selector, Element, NodeList or Element[]
|
|
161
|
+
ScrollAnimate.unobserve(target); // stop observing (elements that never animated are made visible)
|
|
162
|
+
ScrollAnimate.animate(target, opts); // play an animation right now
|
|
163
|
+
ScrollAnimate.refresh(); // rebuild observers, e.g. after configure({ root })
|
|
164
|
+
ScrollAnimate.configure({ ... }); // update global defaults
|
|
165
|
+
ScrollAnimate.destroy(); // disconnect everything
|
|
166
|
+
|
|
167
|
+
const sa = createScrollAnimate({ root: document.querySelector('#scroller') }); // isolated instance
|
|
168
|
+
|
|
169
|
+
// Helpers (tree-shakeable)
|
|
170
|
+
import { sequence, staggerChildren, getScrollProgress } from 'use-scroll-animate';
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Via a `<script>` tag (UMD build), the default instance lives at `ScrollAnimate.default`:
|
|
174
|
+
|
|
175
|
+
```html
|
|
176
|
+
<script src="https://unpkg.com/use-scroll-animate"></script>
|
|
177
|
+
<script>ScrollAnimate.default.init();</script>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## React & Vue
|
|
181
|
+
|
|
182
|
+
```jsx
|
|
183
|
+
import React from 'react';
|
|
184
|
+
import { createReactHooks } from 'use-scroll-animate';
|
|
185
|
+
const { useScrollAnimate, useScrollStagger } = createReactHooks(React);
|
|
186
|
+
|
|
187
|
+
function Card() {
|
|
188
|
+
const ref = useScrollAnimate({ animation: 'zoom-in', easing: 'spring' });
|
|
189
|
+
return <div ref={ref}>Hello</div>;
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
import { ref, onMounted, onUnmounted } from 'vue';
|
|
195
|
+
import { createVueComposables } from 'use-scroll-animate';
|
|
196
|
+
const { useScrollAnimate, useScrollStagger } = createVueComposables({ ref, onMounted, onUnmounted });
|
|
197
|
+
const { animateRef } = useScrollAnimate({ animation: 'fade-in-left' });
|
|
198
|
+
const { staggerRef } = useScrollStagger({ stagger: 60, observeChildren: true }); // <ul ref="staggerRef">
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```jsx
|
|
202
|
+
// React: also animate items appended later
|
|
203
|
+
function Feed({ items }) {
|
|
204
|
+
const ref = useScrollStagger({ animation: 'fade-in-up', stagger: 60, observeChildren: true });
|
|
205
|
+
return <ul ref={ref}>{items.map((i) => <li key={i.id}>{i.title}</li>)}</ul>;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Hooks and composables share the core engine, so `once`, `offset`, custom easing functions, parallax and reduced-motion handling behave exactly like the vanilla API.
|
|
210
|
+
|
|
211
|
+
## Contributing
|
|
212
|
+
|
|
213
|
+
Contributions are always welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/README_ja.md
CHANGED
|
@@ -1,69 +1,106 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
# use-scroll-animate 🚀
|
|
4
|
-
|
|
5
|
-
**軽量(~
|
|
6
|
-
|
|
7
|
-
[](https://github.com/HarrisonCN/use-scroll-animate/releases)
|
|
8
|
-
[](https://github.com/HarrisonCN/use-scroll-animate)
|
|
9
|
-
[](https://opensource.org/licenses/MIT)
|
|
10
|
-
|
|
11
|
-
[English](./README.md) | [简体中文](./README_zh.md)
|
|
12
|
-
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
## なぜ `use-scroll-animate` なのか?
|
|
16
|
-
|
|
17
|
-
2025年、パフォーマンスはすべてです。従来のスクロールアニメーションライブラリは、重い依存関係をバンドルしたり、古いスクロールイベントリスナーに依存したり、特定のフレームワークを強制したりすることがよくあります。
|
|
18
|
-
|
|
19
|
-
`use-scroll-animate` は違います:
|
|
20
|
-
- ⚡ **依存関係なし**:純粋な Vanilla JS/TypeScript。
|
|
21
|
-
- 🚀 **高パフォーマンス**:`IntersectionObserver` とネイティブの `Web Animations API`
|
|
22
|
-
- 🪶 **超軽量**:Gzip
|
|
23
|
-
- 🧩 **フレームワークに依存しない**:Vanilla JS、React、Vue、Svelteなどとシームレスに動作。一流の React Hooks と Vue Composables を内蔵。
|
|
24
|
-
- ♿ **アクセシブル**:`prefers-reduced-motion` を標準でサポート。
|
|
25
|
-
|
|
26
|
-
## インストール
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm install use-scroll-animate
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## クイックスタート (Vanilla JS / HTML)
|
|
33
|
-
|
|
34
|
-
最も簡単な方法は、HTML の `data-sa` 属性を使用することです。
|
|
35
|
-
|
|
36
|
-
```html
|
|
37
|
-
<!-- 1. 要素に data-sa 属性を追加 -->
|
|
38
|
-
<div data-sa data-sa-animation="fade-in-up" data-sa-duration="800">
|
|
39
|
-
スクロールされるとアニメーションします!
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<script type="module">
|
|
43
|
-
// 2. インポートして初期化
|
|
44
|
-
import ScrollAnimate from 'use-scroll-animate';
|
|
45
|
-
ScrollAnimate.init();
|
|
46
|
-
</script>
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## v1.
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# use-scroll-animate 🚀
|
|
4
|
+
|
|
5
|
+
**軽量(~5KB gzipped)、依存関係なしのモダンWeb向けスクロールアニメーションライブラリ。**
|
|
6
|
+
|
|
7
|
+
[](https://github.com/HarrisonCN/use-scroll-animate/releases)
|
|
8
|
+
[](https://github.com/HarrisonCN/use-scroll-animate)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
|
|
11
|
+
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
## なぜ `use-scroll-animate` なのか?
|
|
16
|
+
|
|
17
|
+
2025年、パフォーマンスはすべてです。従来のスクロールアニメーションライブラリは、重い依存関係をバンドルしたり、古いスクロールイベントリスナーに依存したり、特定のフレームワークを強制したりすることがよくあります。
|
|
18
|
+
|
|
19
|
+
`use-scroll-animate` は違います:
|
|
20
|
+
- ⚡ **依存関係なし**:純粋な Vanilla JS/TypeScript。
|
|
21
|
+
- 🚀 **高パフォーマンス**:`IntersectionObserver` とネイティブの `Web Animations API` で駆動。デフォルトではスクロールイベントリスナーなし(オプトインのスクロール進捗モードは、対象要素が画面内にある間だけ passive・rAF スロットルのリスナーを1つ使用)、レイアウトスラッシングなし。
|
|
22
|
+
- 🪶 **超軽量**:Gzip後コア約4.8KB(`sequence`・`staggerChildren`・React/Vue ヘルパーを含む全体で約6.1KB)。
|
|
23
|
+
- 🧩 **フレームワークに依存しない**:Vanilla JS、React、Vue、Svelteなどとシームレスに動作。一流の React Hooks と Vue Composables を内蔵。
|
|
24
|
+
- ♿ **アクセシブル**:`prefers-reduced-motion` を標準でサポート。
|
|
25
|
+
|
|
26
|
+
## インストール
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install use-scroll-animate
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## クイックスタート (Vanilla JS / HTML)
|
|
33
|
+
|
|
34
|
+
最も簡単な方法は、HTML の `data-sa` 属性を使用することです。
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<!-- 1. 要素に data-sa 属性を追加 -->
|
|
38
|
+
<div data-sa data-sa-animation="fade-in-up" data-sa-duration="800">
|
|
39
|
+
スクロールされるとアニメーションします!
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<script type="module">
|
|
43
|
+
// 2. インポートして初期化
|
|
44
|
+
import ScrollAnimate from 'use-scroll-animate';
|
|
45
|
+
ScrollAnimate.init();
|
|
46
|
+
</script>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## v1.4.0 の新機能 ✨
|
|
50
|
+
|
|
51
|
+
- **本当のスクロール進捗 `progressMode: 'scroll'`**(オプトイン):`onProgress` はデフォルトで要素の表示比率を返すため、画面より高い要素では 1 に到達しません。有効にすると、要素の上端がビューポート下端に達したとき `0`、下端がビューポート上端を抜けたとき `1` になります。パララックスも同じ進捗を使用します。HTML では `data-sa-progress="scroll"`。ヘルパー `getScrollProgress(el, root?)` もエクスポートされています。
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
ScrollAnimate.observe('.chapter', {
|
|
55
|
+
progressMode: 'scroll',
|
|
56
|
+
onProgress: (el, p) => el.style.setProperty('--progress', p),
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- **動的に追加された子要素のスタッガー**:`staggerChildren()`(Vanilla)と `useScrollStagger()`(React、**Vue にも新たに対応**)に `observeChildren: true` を追加。`MutationObserver` で後から追加された子要素(無限リスト、「もっと見る」)を検出します。表示前に追加された要素はスタッガーに加わり、表示後に追加された要素はビューポートに入ったときにバッチ単位でスタッガー再生されます。
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
import { staggerChildren } from 'use-scroll-animate';
|
|
64
|
+
const stop = staggerChildren(document.querySelector('#feed'), { stagger: 60, observeChildren: true });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- **タイムライン `sequence()`**:複数要素のアニメーションを連結。各ステップは前のステップの終了後に開始し、`gap` で間隔(負の値で重ね合わせ)、`at` で絶対開始時刻を指定できます。`trigger` を指定するとその要素が表示されたときに一度だけ自動再生します。
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
import { sequence } from 'use-scroll-animate';
|
|
71
|
+
const tl = sequence([
|
|
72
|
+
{ target: '.hero h1', animation: 'fade-in-up', duration: 700 },
|
|
73
|
+
{ target: '.hero p', animation: 'blur-in', gap: -300 },
|
|
74
|
+
{ target: '.hero .btn', animation: 'scale-up', stagger: 80 },
|
|
75
|
+
], { trigger: '.hero' });
|
|
76
|
+
await tl.play(); // すべて完了すると resolve。tl.cancel() で停止し要素は表示されたまま
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- **新しいプリセット**:`scale-up`、`blur-in-up`、`flip-up`、`flip-down`、`rotate-left`、`rotate-right`、clip-path による `clip-up`、`clip-down`、`clip-left`、`clip-right`、`clip-circle`。
|
|
80
|
+
- **メモリ使用量の削減**:`once` 要素はアニメーション開始後に自動でレジストリから削除されます(パララックス/`onProgress` が必要な要素を除く)。`WeakSet` で記憶されるため、`init()`/`observe()` で再生されることはありません。従来の挙動は `createScrollAnimate({ autoUnregister: false })`。
|
|
81
|
+
- **正しい `exports` マップ**:Node ESM は `dist/index.mjs`、CommonJS は `dist/index.js` に解決され、それぞれ対応する型定義付き。従来の `main`/`module`/`unpkg` と `dist/*` のディープインポートも引き続き利用可能。
|
|
82
|
+
|
|
83
|
+
## v1.2.0 の新機能
|
|
84
|
+
|
|
85
|
+
- **一度だけ実行 (Once)**:アニメーション実行後に監視を自動停止し、リソースを節約。
|
|
86
|
+
- **オフセット (Offset)**:要素がビューポートに入ってから何ピクセル後にアニメーションを開始するかを指定可能。
|
|
87
|
+
- **新しいプリセット**:`shimmer`(シマー)、`pulse`(パルス)、`swing`(スイング)を追加。
|
|
88
|
+
- **多言語サポート**:中国語と日本語のドキュメントを追加。
|
|
89
|
+
|
|
90
|
+
## 主な設定
|
|
91
|
+
|
|
92
|
+
| オプション | 型 | デフォルト | 説明 |
|
|
93
|
+
|--------|------|---------|-------------|
|
|
94
|
+
| `animation` | `string` \| `string[]` | `'fade-in-up'` | プリセット名またはプリセットの配列 |
|
|
95
|
+
| `duration` | `number` | `600` | アニメーションの長さ (ms) |
|
|
96
|
+
| `delay` | `number` | `0` | アニメーションの遅延 (ms) |
|
|
97
|
+
| `once` | `boolean` | `true` | 一度だけ実行するかどうか |
|
|
98
|
+
| `offset` | `number` | `0` | アニメーションを開始するビューポートのオフセット (px) |
|
|
99
|
+
| `parallax` | `object` | `{}` | パララックス効果の設定 |
|
|
100
|
+
| `stagger` | `number` | `0` | 同じバッチで表示される兄弟要素ごとの追加遅延 (ms) |
|
|
101
|
+
| `onProgress` | `(el, progress) => void` | – | スクロール進捗のコールバック (0–1) |
|
|
102
|
+
| `progressMode` | `'ratio'` \| `'scroll'` | `'ratio'` | 進捗の計算方法:表示比率または本当のスクロール進捗 |
|
|
103
|
+
|
|
104
|
+
## ライセンス
|
|
105
|
+
|
|
106
|
+
このプロジェクトは MIT ライセンスの下でライセンスされています - 詳細は [LICENSE](LICENSE) ファイルを参照してください。
|