CSS and JavaScript parallax scrolling HTML templates for portfolio sites, agency websites, and product landing pages. Background-position parallax (CSS-only, performant), JavaScript scroll-driven parallax for multi-layer depth, sticky section parallax, fade-on-scroll with IntersectionObserver, and prefers-reduced-motion compliance — production-ready parallax without jQuery or bloated libraries.
Get 180+ Templates — $35Parallax scrolling creates a perception of depth by moving background layers at a slower speed than the foreground as the user scrolls. The effect is visually sophisticated when executed correctly and jarring when not — the two most common failures are poor performance (jank from synchronous scroll handlers on the main thread) and accessibility violations (ignoring prefers-reduced-motion). Modern parallax is built on CSS transforms, requestAnimationFrame, and IntersectionObserver — not the deprecated jQuery scroll handlers of 2012.
The simplest parallax: background-attachment:fixed on a section with a background-image. The background image stays fixed while the content scrolls past it. Performance: acceptable — the compositor can handle fixed backgrounds efficiently. Limitation: on iOS Safari, background-attachment:fixed is ignored for performance reasons — the background renders statically. Alternative for iOS: background-size:cover with a negative-parallax JavaScript approach, or accept the static fallback. CSS background parallax requires no JavaScript and is the correct starting point for a landing page parallax section.
Multiple layers moving at different speeds relative to scroll: background layer at 0.3× scroll speed, midground at 0.6×, foreground at 1× (normal). Implementation: read window.scrollY on scroll. Apply transform:translateY(scrollY * speed) to each layer. Performance critical point: never update DOM properties in a scroll event listener — batch all reads, use requestAnimationFrame. Modern alternative: CSS scroll-driven animations (@keyframes driven by scroll-timeline) — zero JavaScript, compositor-thread-only, smooth 60fps. Scroll-driven animations are supported in Chrome 115+ and Firefox 110+.
Elements that fade in as they enter the viewport. IntersectionObserver API: watch elements with a threshold (e.g., 0.2 — trigger when 20% of the element is visible). On intersection: add a CSS class that transitions opacity from 0 to 1 and translateY from 20px to 0. No scroll event listener: IntersectionObserver fires asynchronously on the main thread without blocking scroll. Each element has a CSS transition: opacity 0.6s ease, transform 0.6s ease. Stagger with a CSS delay: each subsequent element delays by 100ms. Unobserve after the first trigger to avoid re-animating on scroll-back.
@media (prefers-reduced-motion: reduce): disable all parallax and scroll-triggered animations, show static content immediately. In JavaScript: const motionOK = !window.matchMedia('(prefers-reduced-motion:reduce)').matches — check before adding any parallax class or scroll listener. For users with vestibular disorders (balance and spatial orientation issues), parallax and fast-moving scroll effects can cause disorientation or nausea. Respecting prefers-reduced-motion is both an accessibility ethical requirement and increasingly a legal requirement under WCAG 2.2 success criterion 2.3.3.
| Bad Practice | Why It Causes Jank | Fix |
|---|---|---|
| DOM updates in scroll event | Main thread blocked every scroll event | Use requestAnimationFrame |
| Reading layout properties in animation loop | Forces reflow every frame | Read once, write in rAF |
| transform:translateZ(0) on parallax elements | — | Creates composited layer, eliminates repaints |
| jQuery.scroll() for parallax | Synchronous, main thread, 2012 pattern | IntersectionObserver or CSS scroll-timeline |
| background-attachment:fixed on iOS | Ignored by iOS Safari — renders static | JS fallback or accept static |
Commercial licence · No subscription · Instant download · Lifetime updates
Download All 180+ Templates — $35