Technical Guides 13 min read Updated 5 Sep 2026

How 3D scroll websites are actually built

Scroll-scrubbed video, sticky pinning, depth without WebGL, and the performance and accessibility rules that decide whether the result is impressive or unusable.

Desktop monitor and tablet show simple navy and teal page layouts on a bright desk.

Scroll-driven sites are commissioned far more often than they are built well. The failure modes are consistent: the page fights the reader for control of scrolling, the phone battery drains, or the content is trapped inside a canvas where no search engine will ever read it.

None of that is inherent to the technique. It comes from choosing spectacle over structure.

Three techniques, and when each is right

  • Scroll-scrubbed video. A short clip whose playhead is tied to scroll position. Scrolling down advances it, scrolling up reverses it. Best for a cinematic moment you want the reader to control.
  • Sticky-pinned sections. A tall wrapper with a sticky child. The child stays fixed while the wrapper scrolls past, giving you a progress value from 0 to 1 to drive anything. This is the workhorse.
  • CSS 3D depth. Perspective, translateZ and layered parallax. Much cheaper than WebGL, GPU-composited, and sufficient for most "3D" briefs.

Real WebGL (Three.js and similar) is worth it only when you genuinely need arbitrary geometry, lighting or a configurable 3D model. For depth and motion, CSS is lighter, more reliable and far easier to make accessible.

Sticky pinning, without a library

The core pattern is a few lines of CSS. A tall outer element, an inner element that is sticky and exactly one viewport high. Scroll progress through the outer element becomes your animation timeline.

.scene {
  height: 300vh;          /* the scroll distance you want */
  position: relative;
}

.scene__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

Then compute progress in JavaScript and use it to drive whatever you are animating:

function progressOf(scene) {
  const rect = scene.getBoundingClientRect();
  const total = rect.height - window.innerHeight;
  return Math.min(1, Math.max(0, -rect.top / total));
}

Scroll-scrubbed video: the details that matter

Scrubbing a video is easy to demonstrate and easy to get wrong on real devices. Four things decide whether it feels smooth.

  1. Encode with short keyframe intervals. Seeking jumps to the nearest keyframe. A normal web encode places one every two seconds, so scrubbing snaps between them. Re-encode with -g 4 or lower. The file grows; the experience becomes usable.
  2. Serve a size per device. A 4K master is unusable on a phone. Ship 1080p, 720p and 480p variants and choose by viewport and connection.
  3. Set muted, playsinline and preload="auto". Without playsinline, iOS takes the video fullscreen.
  4. Ease the playhead. Do not assign currentTime directly from scroll. Interpolate toward the target in a requestAnimationFrame loop, and the motion becomes smooth instead of stepping.
let target = 0, current = 0;

function tick() {
  current += (target - current) * 0.12;   // ease toward target
  if (Math.abs(target - current) > 0.001) {
    video.currentTime = current * video.duration;
  }
  requestAnimationFrame(tick);
}

The performance budget

Animation is cheap only if you animate the right properties. Anything that forces the browser to recalculate layout on every frame will not hold 60fps on a mid-range phone.

  • Animate transform and opacity only. Both are composited on the GPU.
  • Never animate top, left, width, height or margin — each triggers layout.
  • Read layout values once per frame, then write. Interleaving reads and writes causes forced synchronous layout.
  • Use IntersectionObserver to switch off work for off-screen sections.
  • Use will-change sparingly and remove it afterwards; every promoted layer costs memory.
  • Lazy-load heavy assets. A cinematic clip three sections down should not block the first paint.

Accessibility is not optional here

  • Honour prefers-reduced-motion. Some people experience genuine nausea from parallax and scroll-jacking. Provide a static version with the same content.
  • Never hijack the scroll. Let the native scroll work. Sticky pinning does not take control away; smooth-scroll libraries often do.
  • Keep text as text. Content inside a canvas cannot be selected, searched, translated or read by a screen reader.
  • Keyboard users must reach everything. Test by tabbing through the whole page.
  • Provide a skip link past a long animated sequence.
@media (prefers-reduced-motion: reduce) {
  .scene { height: auto; }
  .scene__stage { position: static; height: auto; }
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

Keeping it indexable

A scroll site ranks exactly like any other site, provided the content is real HTML in the initial response. Problems arise when text is injected by JavaScript after a scroll event that a crawler never fires.

  • Every heading and paragraph should exist in the HTML source before any script runs.
  • Animation should reveal content that is already present, not create it.
  • Check with "view source", not developer tools — the latter shows the page after scripting.
  • Provide normal internal links; a crawler cannot scroll to a section that only exists at 70% progress.

Questions this raises

Often not. Sticky positioning plus a small amount of vanilla JavaScript handles most scroll-driven layouts, with no dependency and a much smaller payload. Reach for a library when you need complex timeline orchestration or genuine 3D geometry.

Only if built carelessly. Reserve space for media to protect CLS, lazy-load anything below the fold to protect LCP, and keep per-frame work small to protect INP.

One to three seconds of footage stretched across two to three viewport heights of scroll. Longer clips need proportionally more scroll distance or the motion becomes too fast to follow.

3D website scroll animation performance web development

Still stuck after reading this? That is usually the point at which it is worth asking someone. Describe your project or ask on WhatsApp.

Keep reading

Related guides

Next step

Tell us what you are working on

Send the brief, the deadline and anything you already have. You will get a reference number straight away and a considered reply, usually within one working day.

  • Fixed quote agreed before any work begins
  • A reference number you can quote on WhatsApp
  • Confidential handling, and an NDA if you want one
  • An honest answer if your deadline is not realistic
Get Expert Help Chat on WhatsApp Email us directly