// ============================================================================
// Stylescape | Parallax Scroll Manager
// ============================================================================
// Creates parallax scrolling effects for background images and elements.
// Supports data-ss-parallax and data-speed attributes for configuration.
// ============================================================================
/**
* Configuration options for ParallaxScrollManager
*/
export interface ParallaxScrollOptions {
/** CSS selector for parallax elements */
selector?: string;
/** Default parallax speed (0-1, lower = slower) */
defaultSpeed?: number;
/** Use transform instead of background-position */
useTransform?: boolean;
/** Enable smooth scrolling behavior */
smooth?: boolean;
}
/**
* Parallax scrolling effect manager for background images.
* Uses requestAnimationFrame for smooth, performant animations.
*
* @example JavaScript
* ```typescript
* const parallax = new ParallaxScrollManager(".parallax")
*
* // Cleanup when done
* parallax.destroy()
* ```
*
* @example HTML with data-speed
* ```html
*
*
Welcome
*
*
*
*
*
*
* ```
*/
export class ParallaxScrollManager {
/** Array of parallax elements */
private elements: HTMLElement[];
/** RAF tick flag to prevent duplicate frames */
private ticking = false;
/**
* Creates a new ParallaxScrollManager instance.
*
* @param parallaxSelector - CSS selector for parallax elements
*/
constructor(parallaxSelector: string) {
this.elements = Array.from(
document.querySelectorAll(parallaxSelector),
);
this.onScroll = this.onScroll.bind(this);
window.addEventListener("scroll", this.onScroll);
}
/**
* Scroll event handler with RAF throttling.
*/
private onScroll(): void {
if (!this.ticking) {
window.requestAnimationFrame(() => {
this.applyParallax();
this.ticking = false;
});
this.ticking = true;
}
}
/**
* Applies parallax effect to all registered elements.
* Reads speed from data-speed attribute (default: 0.5).
*/
private applyParallax(): void {
const scrollY = window.scrollY;
this.elements.forEach((element) => {
const speedAttr = element.getAttribute("data-speed");
const speed = speedAttr ? parseFloat(speedAttr) : 0.5;
if (!isNaN(speed)) {
const yPos = -(scrollY * speed);
element.style.backgroundPosition = `center ${yPos}px`;
}
});
}
/**
* Destroys the manager and removes event listeners.
*/
public destroy(): void {
window.removeEventListener("scroll", this.onScroll);
}
}