Spaces:
Running
Running
| class ParallaxSection extends HTMLElement { | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| :host { | |
| display: block; | |
| position: relative; | |
| height: 100vh; | |
| overflow: hidden; | |
| perspective: 1000px; | |
| } | |
| .parallax-container { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| transform-style: preserve-3d; | |
| } | |
| .parallax-layer { | |
| position: absolute; | |
| inset: 0; | |
| background-size: cover; | |
| background-position: center; | |
| will-change: transform; | |
| } | |
| .content-layer { | |
| position: relative; | |
| z-index: 10; | |
| height: 100%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| </style> | |
| <div class="parallax-container"> | |
| <div class="parallax-layer layer-1"></div> | |
| <div class="parallax-layer layer-2"></div> | |
| <div class="parallax-layer layer-3"></div> | |
| <div class="content-layer"> | |
| <slot></slot> | |
| </div> | |
| </div> | |
| `; | |
| this.layers = [ | |
| this.shadowRoot.querySelector('.layer-1'), | |
| this.shadowRoot.querySelector('.layer-2'), | |
| this.shadowRoot.querySelector('.layer-3') | |
| ]; | |
| // Set background images from attributes | |
| if (this.hasAttribute('layer1')) { | |
| this.layers[0].style.backgroundImage = `url('${this.getAttribute('layer1')}')`; | |
| } | |
| if (this.hasAttribute('layer2')) { | |
| this.layers[1].style.backgroundImage = `url('${this.getAttribute('layer2')}')`; | |
| } | |
| if (this.hasAttribute('layer3')) { | |
| this.layers[2].style.backgroundImage = `url('${this.getAttribute('layer3')}')`; | |
| } | |
| // Parallax effect | |
| window.addEventListener('scroll', () => { | |
| const scrollY = window.scrollY; | |
| const rect = this.getBoundingClientRect(); | |
| const offsetTop = rect.top + window.scrollY; | |
| const viewportHeight = window.innerHeight; | |
| // Only animate when section is in view | |
| if (scrollY + viewportHeight > offsetTop && scrollY < offsetTop + rect.height) { | |
| const progress = (scrollY - offsetTop + viewportHeight) / (viewportHeight + rect.height); | |
| this.layers.forEach((layer, index) => { | |
| const depth = (index + 1) * 0.2; | |
| const translateY = progress * 100 * depth; | |
| layer.style.transform = `translate3d(0, ${translateY}px, 0)`; | |
| }); | |
| } | |
| }); | |
| } | |
| } | |
| customElements.define('parallax-section', ParallaxSection); |