liveBook · Manning

Parallax effect

As explained in Math for Web Design

A parallax effect is a visual effect in which elements appear to move at different rates as the viewing position changes.

A parallax effect creates depth by moving layered elements at different rates as the viewer scrolls or as an animation advances. Distant backgrounds move more slowly than foreground content, while closer simulated objects move faster. section 10.2.4 section 14.2.2

A geometric implementation ties movement directly to depth:

  • Assign each layer a data-parallax value. The update uses parallaxOffset = scrollTop × (1 − depth), so smaller depth values produce greater movement. section 10.2.4
  • Respect prefers-reduced-motion: reduce and limit the effect on smaller screens because motion can affect people with vestibular problems and can be difficult on mobile. section 10.2.4

Animated star field

A canvas star field gives every star a random z depth. Speed uses 0.25 / z, radius uses (maxDepth − z) / maxDepth × 2, and opacity uses (maxDepth − z) / maxDepth. Nearby stars therefore move faster, appear larger, and look brighter than distant stars. section 14.2.2

Listing 10.3 Geometric parallax scrolling
initializeLayers() {
    return Array.from(document
      .querySelectorAll('[data-parallax]'))    #1
      .map(element => {
          const depth = parseFloat(element.dataset    #2
                        .parallax) || 1;     #2
          const rect = element.getBoundingClientRect();    #3

          return {
            element: element,
            depth: depth,
            initialY: rect.top + window.scrollY,    #4
            initialX: rect.left     #4
        };
    });
}

setUpEventListeners() {
    window.addEventListener('scroll', () => {    #5
        if (!this.isScrolling) {
            requestAnimationFrame(() => {    #6
                this.updateParallax();     #6
                this.isScrolling = false;
            });
            this.isScrolling = true;
        }
    }, { passive: true });
}

updateParallax() {
    const scrollTop = window.scrollY;    #7
    const windowHeight = window.innerHeight;    #8

    this.layers.forEach(layer => {
        const elementTop = layer.initialY - scrollTop;    #9
        const elementBottom = elementTop +      #9
                            layer.element.offsetHeight;     #9

        if (elementBottom >= -windowHeight &&    #10
            elementTop <= windowHeight * 2) {     #10

            const parallaxOffset = scrollTop *    #11
                                   (1 - layer.depth);     #11

            let transform = `translate3d(0, ${parallaxOffset}px, 0)`;    #12
            layer.element.style.transform = transform;     #12
        }
    });
}

Inspect the complete geometric implementation for layer discovery, initial-position measurement, passive scroll handling, and requestAnimationFrame updates. section 10.2.4

Listing 14.5b Creating a generative star field background effect (part 2)
function animate() {
    ctx.clearRect(0, 0, canvas.width, 
                 ➥    canvas.height);  #1

    stars.forEach(star => {

        star.x -= star.speed;  #2

        if (star.x < 0) {  #3
            star.x = canvas.width;   #3
            star.y = Math.random() * canvas.height;  #4
        }

        ctx.beginPath();  #5
        ctx.arc(star.x, star.y, star.radius,  #5
                ➥    0, Math.PI * 2);   #5
        ctx.fillStyle = `rgba(255, 255, 255,  #5
                        ➥    ${star.opacity})`;   #5
        ctx.fill();   #5
    }); #5

    requestAnimationFrame(animate);
}

window.addEventListener('resize', () => {  #6
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    stars.forEach(star => {  #7
        if (star.x > canvas.width) star.x = Math.random() * canvas.width;
        if (star.y > canvas.height) star.y = Math.random() * canvas.height;
    });
});

canvas.style.background = 'black';
animate();

Inspect the animation loop that clears the canvas, advances stars, wraps them at the edge, redraws them, and responds to resizing. section 14.2.2

How Math for Web Design covers it

How deep it goes
Explains depth-based formulas and JavaScript update loops, while stopping short of a full derivation of the underlying geometry.
Examples
Uses layered scrolling content and a generative star field with depth-dependent speed, size, and opacity.
What you can do after
Build it from scratch using data attributes, scroll calculations, DOM layers, or a canvas animation loop.
How it connects
Connects scroll events, vectors, DOM positioning, requestAnimationFrame, canvas animation, and simulated depth.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Math for Web Design. The section links point to the parts of the book it draws on.