🎬 Module 1: Parallax Scrolling

Adding Depth Like a Movie - Using Bootstrap 5.3

Bootstrap 5.3 CSS Parallax JavaScript Parallax

Parallax Background (Fixed)

Scroll to see the effect

What Is Parallax Scrolling?

Parallax scrolling makes backgrounds move slower than foreground content as you scroll. It's like looking out a car window: trees (background) move slower than the road (foreground). This adds depth and makes sites feel dynamic.

Bootstrap + Parallax Technique

HTML with Bootstrap:

<div class="parallax-section d-flex align-items-center justify-content-center text-white">
  <div class="container">
    <h2 class="display-3 fw-bold">Parallax Content</h2>
  </div>
</div>

Custom CSS for Parallax:

.parallax-section {
  background-image: url('...');
  min-height: 500px;
  background-attachment: fixed; /* KEY! */
  background-position: center;
  background-size: cover;
}

✅ Bootstrap Utilities Used

  • d-flex align-items-center – Flexbox centering
  • container – Responsive width
  • display-3 fw-bold – Typography
  • text-white – Text color
  • py-5 – Vertical padding

⚠️ Key Points

  • Bootstrap handles layout and responsive design
  • Custom CSS adds the parallax effect
  • Mobile devices: parallax automatically disabled
  • Respects prefers-reduced-motion

Normal Scrolling Background

Compare with the parallax section above

Comparison: Normal Scrolling

The green section above uses background-attachment: scroll (the default). Notice how it scrolls with the content instead of staying fixed. This is the traditional approach.

📊 Key Differences:

Technique Implementation Mobile Support Complexity
Parallax (fixed) background-attachment: fixed Limited ⭐ Simple
Normal (scroll) background-attachment: scroll ✅ Works ⭐ Simple
🌌
☁️
JavaScript Parallax
Scroll to see 3 layers moving at different speeds

Technique 2: JavaScript Parallax with Multiple Layers

The section above uses JavaScript with transform: translateY() to move three separate layers at different speeds. This creates a more sophisticated depth effect than pure CSS.

Step 1: HTML Structure with data-speed

<div class="parallax-js-section">
  <!-- Each layer moves at different speed -->
  <div class="parallax-layer layer-back" data-speed="0.2">🌌</div>
  <div class="parallax-layer layer-middle" data-speed="0.5">☁️</div>
  <div class="parallax-layer layer-front" data-speed="0.8">Text</div>
</div>

Step 2: JavaScript reads data-speed and applies transform

// 1. Select all layers
const parallaxLayers = document.querySelectorAll('.parallax-layer');

// 2. On scroll, update each layer's position
function updateParallax() {
  parallaxLayers.forEach((layer) => {
    // Read the speed value from HTML attribute
    const speed = parseFloat(layer.dataset.speed);
    
    // Calculate how much to move this layer
    const scrolled = window.pageYOffset;
    const yPos = scrolled * speed * 0.5;
    
    // Apply the transform
    layer.style.transform = `translateY(${yPos}px)`;
  });
}

// 3. Listen to scroll events efficiently
window.addEventListener('scroll', () => {
  requestAnimationFrame(updateParallax);
}, { passive: true });

✅ Advantages

  • Precise Control: Control exact speed per layer
  • Multiple Elements: Move any HTML element
  • Works on Mobile: Unlike CSS fixed background
  • Complex Animations: Combine with opacity, scale, etc.

⚠️ Considerations

  • Requires JavaScript (fallback needed)
  • Use requestAnimationFrame for performance
  • Respect prefers-reduced-motion
  • Bootstrap's utilities still helpful for layout

♿ Accessibility: Respecting User Preferences

What is prefers-reduced-motion?

prefers-reduced-motion is a CSS media query that detects if a user has requested reduced motion in their operating system settings. Users can enable this in:

  • macOS: System Preferences → Accessibility → Display → Reduce motion
  • Windows: Settings → Ease of Access → Display → Show animations
  • iOS: Settings → Accessibility → Motion → Reduce Motion
  • Android: Settings → Accessibility → Remove animations

How This Demo Respects It

This demo automatically disables parallax effects when users have motion reduction enabled:

// 1. Detect user's motion preference
const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
);
let isReducedMotion = prefersReducedMotion.matches;

// 2. Disable CSS parallax if needed
function handleMotionPreference() {
  if (isReducedMotion) {
    // Change fixed backgrounds to scroll normally
    document.querySelectorAll('.parallax-bg').forEach((el) => {
      el.style.backgroundAttachment = 'scroll';
    });
  }
}

// 3. Don't initialize JavaScript parallax if reduced motion
function initParallax() {
  if (isReducedMotion) {
    console.log('Parallax disabled: user prefers reduced motion');
    return; // Exit without setting up animations
  }
  // ... rest of parallax code
}

// 4. Listen for preference changes during session
prefersReducedMotion.addEventListener('change', (e) => {
  isReducedMotion = e.matches;
  // Update animations accordingly
});

Test It Yourself

  1. Open your browser's DevTools (F12)
  2. Go to the Console tab and type: window.matchMedia('(prefers-reduced-motion: reduce)').matches
  3. It returns true if reduce motion is enabled, false otherwise
  4. Enable "Reduce motion" in your OS settings and refresh this page
  5. Notice how all parallax effects are disabled!

💡 Best Practices for Accessibility

  • Always respect prefers-reduced-motion - It's a user request, not a suggestion
  • Provide fallbacks: Ensure content is accessible without motion
  • Don't just reduce: Disable motion entirely when requested
  • Test thoroughly: Check with motion reduction enabled
  • Bootstrap helps: Use Bootstrap's utilities for structure that works regardless of motion