Baike.dev
All toolsTrendingOpen sourceNewsSubmit
Log in
< 返回工具列表
S

ScrollMagic

> 编程语言
开源

The javascript library for magical scroll interactions.

14.9K stars0 点赞0 次浏览
访问官网GitHub

工具介绍

The javascript library for magical scroll interactions.

# ScrollMagic 3 ### The lightweight library for magical scroll interactions > **Looking for ScrollMagic v2?** The legacy version is on the [`v2-stable`](https://github.com/janpaepke/ScrollMagic/tree/v2-stable) branch. ScrollMagic tells you where an element is relative to the viewport as the user scrolls — and fires events when that changes. It's a convenience wrapper around [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) and [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) that handles the performance pitfalls and counter-intuitive edge cases for you. ### Not an animation library – unless you want it to be By itself, ScrollMagic doesn't animate anything. It provides precise scroll-position data and events — what you do with them is up to you. If you're looking for a ready-made scroll animation solution, check out [GSAP ScrollTrigger](https://gsap.com/docs/v3/Plugins/ScrollTrigger/), [Motion](https://motion.dev/docs/scroll), or [anime.js](https://animejs.com/). For pure CSS-driven scroll animations, see native [scroll-driven animations](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll-driven_animations) (not yet supported in all browsers). ScrollMagic complements them by providing cross-browser support, event callbacks, progress values, and state management that the native API doesn't cover. ScrollMagic is a general-purpose, framework-agnostic, zero-dependency foundation for scroll-driven UX — what you do with it is entirely up to you: class toggles, animations, lazy loading, parallax, scroll-linked video, behavioural tracking, or anything else. ### Why ScrollMagic? - Tiny footprint, zero dependencies - Free to use ([open source](LICENSE.md)) - Optimized for performance (shared observers, batched rAF, single-frame updates) - Built for modern browsers, mobile compatible - Native TypeScript support - SSR safe - Works with any scroll container (window or custom element) - Horizontal and vertical scrolling - Plugin system for extensibility - Framework agnostic — works with React, Vue, vanilla JS, anything ## Installation ```sh npm install scrollmagic@next ``` ## Quick Start ```js import ScrollMagic from 'scrollmagic'; new ScrollMagic({ element: '#my-element' }) .on('enter', () => console.log('visible!')) .on('leave', () => console.log('gone!')) .on('progress', e => console.log(`${(e.target.progress * 100).toFixed(0)}%`)); ``` ## How It Works ScrollMagic uses two sets of bounds to define the active range: - **Container bounds** — a zone on the scroll container, defined by `containerStart` and `containerEnd` - **Element bounds** — a zone on the tracked element, defined by `elementStart` and `elementEnd` Progress goes from `0` to `1` as the element bounds pass through the container bounds. Events fire on enter, leave, and progress change. ### Contain and Intersect The two most common configurations are **contain** and **intersect**. They differ in where the container bounds are positioned: #### Contain (default when `element` is `null`) The container bounds match the viewport edges — `containerStart` and `containerEnd` are both at `'here'` (`0%`). Progress goes from 0 to 1 while one fully **contains** the other: either the element is fully visible inside the viewport, or the element fully covers the viewport. Typical uses: scroll progress bars, parallax, scroll-linked video, scroll-driven storytelling.
#### Intersect (default when `element` is set) The container bounds span the full viewport — `containerStart` and `containerEnd` are at `'opposite'` edges (`100%`). Progress goes from 0 to 1 while the element **intersects** with the viewport: starting when its leading edge enters and ending when its trailing edge leaves. Typical uses: enter/leave animations, lazy loading, class toggles, visibility tracking.
#### Not just defaults While _contain_ and _intersect_ are the inferred defaults, you can also configure them explicitly — for example setting `containerStart: 0, containerEnd: 0` on an instance that has an element to get contain behaviour, or mixing container and element insets for custom tracking zones. The two configurations are **useful mental models, not rigid modes**. #### Native scroll-driven animation ranges If you're familiar with [CSS scroll-driven animations](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll-driven_animations), here's how the native `view()` timeline ranges map to ScrollMagic configurations: | Native range | ScrollMagic equivalent | | ------------ | ---------------------- | | `cover` | _intersect_ default — `containerStart: 'opposite', containerEnd: 'opposite'` | | `contain` | _contain_ default — `containerStart: 0, containerEnd: 0` | | `entry` | `containerStart: 'opposite', containerEnd: 0` — container zone collapses to the trailing edge | | `exit` | `containerStart: 0, containerEnd: 'opposite'` — container zone collapses to the leading edge | The native `entry-crossing` and `exit-crossing` ranges are equivalent to `entry` and `exit` above — the distinction only applies when subdividing a single native timeline, not when defining standalone tracking ranges. ## Options All options are optional. They can be passed to the constructor and updated at any time via setters or `.modify()`. | Option | Type | Default | Description | | ---------------- | -------------------------------------- | -------------------------- | ----------------------------------------------------- | | `element` | `Element \| string \| null` | first child of `container` | The tracked element (or CSS selector). Selectors match only the first element — create one instance per element to track multiple. | | `elementStart` | `number \| string \| function` | `0` | Start **inset** on the element. | | `elementEnd` | `number \| string \| function` | `0` | End **inset** on the element. | | `container` | `Window \| Element \| string \| null` | `window` | The scroll container (or CSS selector). Selectors use the first match. | | `containerStart` | `number \| string \| function \| null` | inferred (see below) | Start **inset** on the scroll container. | | `containerEnd` | `number \| string \| function \| null` | inferred (see below) | End **inset** on the scroll container. | | `vertical` | `boolean` | `true` | Scroll axis. `true` = vertical, `false` = horizontal. | **Inset values** work like CSS `top`/`bottom`: positive values offset inward from the respective edge in the tracked direction. Accepted value types: - **Numbers** — pixel values (e.g. `50`) - **Strings** — percentage or pixel strings (e.g. `'50%'`, `'20px'`), relative to the parent size (scroll container for container options, element for element options) - **Named positions** — `'here'` (0%), `'center'` (50%), `'opposite'` (100%) - **Functions** — `(size) => number` for dynamic computation **`null` means infer:** For `element`, `container`, `containerStart`, or `containerEnd`, setting it to `null` resets them to their inferred default. For `containerStart`/`containerEnd` the inferred values depend on `element`: - **`element` is `null`** → defaults to [**contain**](#contain-default-when-element-is-null): the element is inferred as the first child of the container (for `window` this is `document.body`), container offsets are `'here'` (0%), mapping progress to overall scroll position. - **`element` is not `null`** → defaults to [**intersect**](#intersect-default-when-element-is-set): container offsets are `'opposite'` (100%), tracking the element as it scrolls through the full viewport. ## Events Subscribe with `.on()`, `.off()`, or `.subscribe()` (returns an unsubscribe function). Pass `{ once: true }` to auto-remove the listener after its first invocation. Calling `.off()` or the unsubscribe function after the listener has already been removed (e.g. after a `once` listener fires) is a safe no-op. | Event | When | | ---------- | -------------------------------------------------------- | | `enter` | Element enters the active zone (progress leaves 0 or 1) | | `leave` | Element leaves the active zone (progress reaches 0 or 1) | | `progress` | Progress value changes while in the active zone | Every event provides: ```ts event.target; // the ScrollMagic instance (access all properties, e.g. event.target.progress, event.target.element) event.type; // 'enter' | 'leave' | 'progress' event.direction; // 'forward' | 'reverse' event.location; // 'start' | 'inside' | 'end' ``` ## Examples ``` … ``` ## API ``` … ``` ## When to use `refresh()` ScrollMagic automatically tracks element size changes (via `ResizeObserver`) and scroll position changes. But some layout changes are invisible to these observers — they change an element's **position** without changing its **size** or triggering a scroll event. Call `refresh()` (or `ScrollMagic.refreshAll()`) after: - **CSS position/margin/padding changes** — `element.style.marginTop = '20px'` - **CSS class toggles that affect layout** — `element.classList.add('expanded')` - **DOM structure changes** — siblings added/removed above the element, shifting its position - **Images loading without explicit dimensions** — an `` above the tracked element loads and expands, pushing it down - **Font loading** — `document.fonts.ready.then(() => ScrollMagic.refreshAll())` - **Route changes in SPAs** — content swap changes scroll height - **Dynamic content loading** — CMS-injected content, third-party widgets ```js // After changing a style that affects position element.style.marginTop = '100px'; sm.refresh(); // After fonts finish loading (affects text reflow) document.fonts.ready.then(() => ScrollMagic.refreshAll()); // After a framework re-render that changes layout onRouteChange(() => ScrollMagic.refreshAll()); ``` Note that `refresh()` is only needed if you want bounds to update **before the next scroll event**. If the user keeps scrolling, element positions are re-read on every scroll frame anyway. `refresh()` matters when layout changes while tracking is active and the scroll position stays the same — e.g. toggling a class or injecting content without any scrolling. `refresh()` is asynchronous — it schedules recalculation for the next animation frame and returns immediately. Multiple `refresh()` calls within the same frame are batched automatically. ## Plugins ScrollMagic has a plugin system for extending instance behaviour. ```ts sm.addPlugin(myPlugin); sm.removePlugin(myPlugin); ``` See [PLUGINS.md](PLUGINS.md) for the full plugin authoring guide. ## Browser Support Chrome 73+, Firefox 69+, Safari 13.1+, Edge 79+ (aligned to `ResizeObserver` support). ## License MIT — [Jan Paepke](https://janpaepke.de)

核心特点

  • •Tiny footprint, zero dependencies
  • •Free to use (open source)
  • •Optimized for performance (shared observers, batched rAF, single-frame updates)
  • •Built for modern browsers, mobile compatible
  • •Native TypeScript support
  • •SSR safe
  • •Works with any scroll container (window or custom element)
  • •Horizontal and vertical scrolling
  • •Plugin system for extensibility
  • •Framework agnostic — works with React, Vue, vanilla JS, anything

> 标签

TypeScript

暂无评论,来聊聊你的看法吧

> 工具信息

发布日期2026年8月1日
最后更新2026年9月9日
分类编程语言
定价开源

> 相关工具

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言
Baike.dev

baike.dev helps you discover great languages, frameworks, databases, DevOps and cloud-native tools.

Quick links

  • Home
  • All tools
  • Trending
  • Open source

About

  • About us
  • Community
  • News

Contribute

Found a great developer tool? Share it with the community.

Submit a tool
© 2026 baike.dev Developer EncyclopediaUpdated daily · Discover great developer tools