logo

useScroll

useScroll is used to create scroll-linked animations, like progress indicators and parallax effects.

Note: When scroll-linked animations are powered by the scroll function from motion, animations using opacity or transform CSS properties can be hardware accelerated.

<script>
  import { useScroll, useSpring } from '@humanspeak/svelte-motion'

  const { scrollYProgress } = useScroll()
  const scaleX = useSpring(scrollYProgress)
</script>

<div
  style="position: fixed; top: 0; left: 0; right: 0; height: 5px;
         background: #ff0088; transform-origin: left;
         transform: scaleX({$scaleX});"
/>
<script>
  import { useScroll, useSpring } from '@humanspeak/svelte-motion'

  const { scrollYProgress } = useScroll()
  const scaleX = useSpring(scrollYProgress)
</script>

<div
  style="position: fixed; top: 0; left: 0; right: 0; height: 5px;
         background: #ff0088; transform-origin: left;
         transform: scaleX({$scaleX});"
/>

Usage

Import

<script>
  import { useScroll } from '@humanspeak/svelte-motion'
</script>
<script>
  import { useScroll } from '@humanspeak/svelte-motion'
</script>

useScroll returns four reactive Svelte stores:

StoreDescription
scrollXHorizontal scroll position in pixels
scrollYVertical scroll position in pixels
scrollXProgressHorizontal scroll progress between 0 and 1
scrollYProgressVertical scroll progress between 0 and 1

Page scroll

By default, useScroll tracks the page scroll position:

<script>
  import { useScroll, useSpring } from '@humanspeak/svelte-motion'

  const { scrollYProgress } = useScroll()
  const scaleX = useSpring(scrollYProgress)
</script>

<div
  style="position: fixed; top: 0; left: 0; right: 0; height: 5px;
         background: #ff0088; transform-origin: left;
         transform: scaleX({$scaleX});"
/>
<script>
  import { useScroll, useSpring } from '@humanspeak/svelte-motion'

  const { scrollYProgress } = useScroll()
  const scaleX = useSpring(scrollYProgress)
</script>

<div
  style="position: fixed; top: 0; left: 0; right: 0; height: 5px;
         background: #ff0088; transform-origin: left;
         transform: scaleX({$scaleX});"
/>
1
2
3
4
5

Element scroll

Track the scroll position of a specific scrollable element by passing it as the container:

<script>
  import { useScroll } from '@humanspeak/svelte-motion'

  let containerEl

  const { scrollYProgress } = useScroll({ container: containerEl })
</script>

<div bind:this={containerEl} style="overflow-y: scroll; height: 300px;">
  <!-- tall content -->
</div>

<div>Scroll progress: {$scrollYProgress}</div>
<script>
  import { useScroll } from '@humanspeak/svelte-motion'

  let containerEl

  const { scrollYProgress } = useScroll({ container: containerEl })
</script>

<div bind:this={containerEl} style="overflow-y: scroll; height: 300px;">
  <!-- tall content -->
</div>

<div>Scroll progress: {$scrollYProgress}</div>

Element position

Track a target element’s position as it scrolls within its container (or the viewport):

<script>
  import { useScroll } from '@humanspeak/svelte-motion'

  let targetEl

  const { scrollYProgress } = useScroll({ target: targetEl })
</script>

<div bind:this={targetEl}>
  <div style="opacity: {$scrollYProgress}">
    Fades in as you scroll to this element
  </div>
</div>
<script>
  import { useScroll } from '@humanspeak/svelte-motion'

  let targetEl

  const { scrollYProgress } = useScroll({ target: targetEl })
</script>

<div bind:this={targetEl}>
  <div style="opacity: {$scrollYProgress}">
    Fades in as you scroll to this element
  </div>
</div>

Scroll offsets

When tracking an element’s position, the offset option defines when the tracking starts and ends. Each offset is a pair of intersections — one for the target and one for the container:

<script>
  import { useScroll } from '@humanspeak/svelte-motion'

  let targetEl

  // Start when target enters bottom of viewport,
  // end when target reaches top of viewport
  const { scrollYProgress } = useScroll({
    target: targetEl,
    offset: ['start end', 'end start']
  })
</script>
<script>
  import { useScroll } from '@humanspeak/svelte-motion'

  let targetEl

  // Start when target enters bottom of viewport,
  // end when target reaches top of viewport
  const { scrollYProgress } = useScroll({
    target: targetEl,
    offset: ['start end', 'end start']
  })
</script>

Named offset values:

ValueDescription
"start"Top edge of the element
"center"Center of the element
"end"Bottom edge of the element

You can also use numbers (0 to 1) and pixel values ("100px").

Performance

Scroll animations work best with CSS properties that can be GPU-accelerated:

  • transform (translateX, translateY, scale, rotate)
  • opacity

These properties don’t trigger layout or paint, so the browser can animate them on the compositor thread for smooth 60fps performance even during rapid scrolling.

Options

OptionTypeDescription
containerHTMLElementScrollable element to track. Defaults to the page.
targetHTMLElementTarget element to track position of within the container.
offsetstring[]Array of scroll offsets defining when tracking starts and ends.
axis'x' \| 'y'Which axis to use for the single-axis progress callback. Defaults to 'y'.

API Reference

Signature

useScroll(options?: UseScrollOptions): {
  scrollX: Readable<number>
  scrollY: Readable<number>
  scrollXProgress: Readable<number>
  scrollYProgress: Readable<number>
}
useScroll(options?: UseScrollOptions): {
  scrollX: Readable<number>
  scrollY: Readable<number>
  scrollXProgress: Readable<number>
  scrollYProgress: Readable<number>
}

Returns

An object with four Svelte Readable<number> stores.

See also


Based on Motion’s useScroll API.