Components

Animation and scroll effects

Scroll/resize coalesced to requestAnimationFrame: read --scroll-progress, data-scroll-progress, and body classes from wckd-ui.js. Idle pass toggles in-view on .animate; pair animate image-zoom on .background-image blocks for the built-in zoom.

Download & setup

Load the kit from Get Started; use the style guide for utilities and tokens while wiring this component.

Default implementation

Live body hooks on this page

WCKD_BODY_SCROLL coalesces scroll/resize work to requestAnimationFrame. Read --scroll-progress, data-scroll-progress, and classes like at-top / scrolling-down from document.body in CSS or light scripts. In-view behaviour on .animate is covered under configuration options below.

Body: progress, data attribute, direction

Scroll this page, values read from the live body node. Full walkthrough: style guide.

at-top scrolling-down scrolling-up at-bottom

Document progress (0 = top, 1 = bottom):

Markup

/* body ,  always updated when wckd-ui.js runs */
/* --scroll-progress, data-scroll-progress, .at-top, .at-bottom, .scrolling-up, .scrolling-down */

header.hero {
  transform: scaleX(var(--scroll-progress, 0));
  transform-origin: left center;
}

Configuration options

Default block: body scroll vars. Optional blocks: add animate (and optional image-zoom on .background-image); demos use inline <style> for motion only.

In-view: .animate

Elements with class animate are observed by wckdToggleInViewClass; when enough of the element is visible, the script adds in-view (and removes it when leaving). You define resting and .in-view looks, this demo uses scoped inline CSS for lift, slide, fade, blur, and scale-on-box patterns.

Scroll until each tile crosses the viewport. Default visibility threshold is 0.4 unless you set data-threshold on the node.

Lift (translateY)

Lift + fade

Slide (translateX)

Slide from inline start

Fade only

Opacity only

Blur in

Blur + slight scale

Scale (whole box)

Gentle scale

Pop easing

Overshoot curve

Earlier threshold

Rotate + scale · 0.2

Markup

<style>/* scope under a wrapper id in your theme */</style>
<div class="animate my-reveal">…</div>

/* CSS */
.my-reveal { opacity: 0; transform: translateY(12px); transition: … }
.my-reveal.in-view { opacity: 1; transform: none; }

In-view: .animate.image-zoom (still)

Add image-zoom alongside animate on the same element. The kit scales .background-image img from transform: scale(1) to 1.1 when in-view is on, Ken Burns–style motion on a hero or card still, without a second JS selector.

Use animate image-zoom on a wrapper that contains .background-image with a cover img. Rules live in wckd-ui.css; the script only toggles in-view on .animate.

Still zooms in when in-view applies

Markup

<div class="animate image-zoom relative height-30 hide-overflow round">
  <div class="background-image" aria-hidden="true">
    <img src="/media/hero.jpg" width="1600" height="900" alt="" />
  </div>
  <div class="overlay relative tint-dark pad">…</div>
</div>

When to use

  • Reading progress, gradient read-lines, and chapter position indicators.
  • Tightening sticky header shadow on scrolling-down or showing a footer CTA at at-bottom.
  • Entrance motion without a framework, using only CSS and in-view on .animate.

Implementation notes

  • Body scroll tracking is not a separate bootstrap step; it runs when wckd-ui.js loads (flushScrollDirection on scroll/resize).
  • .hide-and-seek in wckd-ui.css uses body.scrolling-down / scrolling-up for the auto-hiding site header.
  • Threshold for in-view: parseFloat(parentCarousel?.dataset.threshold || el.dataset.threshold || '0.4') in wckdToggleInViewClass.
  • On very short pages, at-top and at-bottom can both be true; prefer at-top to mean “not really scrolled” for header chrome.

Developer checklist

  • Confirm the idle bootstrap still calls wckdToggleInViewClass when the page uses .animate nodes.
  • Do not re-bind window scroll for the same progress math, read body in CSS or use data-scroll-progress in targeted scripts.
  • iOS overscroll can momentarily change edge flags; do not use them as the sole trigger for one-shot modals without debounce.

← All components