Parallax
Snap does not modify element styles by default, but it provides a set of optional parallax utilities for DOM elements.
Parallax effects are enabled using data- attributes.
Do not apply parallax directly to the slide element. Use inner wrappers instead.
Demos
Skew Parallax
HTML
<div class="fullpage-center">
<div class="carousel" id="carousel">
<div class="slide">
<div class="wrap" data-snap-parallax-skew="-40" data-snap-parallax-skew-min="-40" data-snap-parallax-skew-max="40" data-snap-parallax-skew-scope="const" data-snap-parallax-skew-impulse="5" data-snap-parallax-skew-directional>1</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-skew="-40" data-snap-parallax-skew-min="-40" data-snap-parallax-skew-max="40" data-snap-parallax-skew-scope="const" data-snap-parallax-skew-impulse="5" data-snap-parallax-skew-directional>2</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-skew="-40" data-snap-parallax-skew-min="-40" data-snap-parallax-skew-max="40" data-snap-parallax-skew-scope="const" data-snap-parallax-skew-impulse="5" data-snap-parallax-skew-directional>3</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-skew="-40" data-snap-parallax-skew-min="-40" data-snap-parallax-skew-max="40" data-snap-parallax-skew-scope="const" data-snap-parallax-skew-impulse="5" data-snap-parallax-skew-directional>4</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-skew="-40" data-snap-parallax-skew-min="-40" data-snap-parallax-skew-max="40" data-snap-parallax-skew-scope="const" data-snap-parallax-skew-impulse="5" data-snap-parallax-skew-directional>5</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-skew="-40" data-snap-parallax-skew-min="-40" data-snap-parallax-skew-max="40" data-snap-parallax-skew-scope="const" data-snap-parallax-skew-impulse="5" data-snap-parallax-skew-directional>6</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-skew="-40" data-snap-parallax-skew-min="-40" data-snap-parallax-skew-max="40" data-snap-parallax-skew-scope="const" data-snap-parallax-skew-impulse="5" data-snap-parallax-skew-directional>7</div>
</div>
</div>
</div>
CSS
.carousel {
--size: clamp(max(10rem, 25vw), 50vh, 50vw);
position: relative;
width: 100%;
height: var(--size);
opacity: 0;
transition: opacity 0.25s linear;
}
.carousel.ready {
opacity: 1;
}
.slide {
position: absolute;
top: 0;
left: 0;
width: var(--size);
height: 100%;
}
.slide .wrap {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.08);
border-radius: 0.5rem;
font-size: 1rem;
font-weight: bold;
color: #ececec;
}
.slide:nth-child(1) .wrap {
background: var(--gradient-slide-1, #000);
}
.slide:nth-child(2) .wrap {
background: var(--gradient-slide-2, #000);
}
.slide:nth-child(3) .wrap {
background: var(--gradient-slide-3, #000);
}
.slide:nth-child(4) .wrap {
background: var(--gradient-slide-4, #000);
}
.slide:nth-child(5) .wrap {
background: var(--gradient-slide-5, #000);
}
.slide:nth-child(6) .wrap {
background: var(--gradient-slide-6, #000);
}
.slide:nth-child(7) .wrap {
background: var(--gradient-slide-7, #000);
}
JavaScript
import {
Snap
} from "vevet";
const container = document.getElementById("carousel");
const carousel = new Snap({
container,
origin: "center",
loop: true,
gap: "1.25rem",
lerp: 0.2,
freemode: true,
shortSwipes: false,
grabCursor: true
});
container.classList.add("ready");
carousel.on("update", () => {
carousel.slides.forEach(({
element,
coord,
isVisible
}) => {
element.style.transform = `translate(${coord}px, 0)`;
});
});
Parallax Gap
HTML
<div class="fullpage-center">
<div class="carousel" id="carousel">
<div class="slide">
<div class="wrap" data-snap-parallax-x="-50%" data-snap-parallax-x-scope="none" data-snap-parallax-x-impulse="3">1</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-x="-50%" data-snap-parallax-x-scope="none" data-snap-parallax-x-impulse="3">2</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-x="-50%" data-snap-parallax-x-scope="none" data-snap-parallax-x-impulse="3">3</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-x="-50%" data-snap-parallax-x-scope="none" data-snap-parallax-x-impulse="3">4</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-x="-50%" data-snap-parallax-x-scope="none" data-snap-parallax-x-impulse="3">5</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-x="-50%" data-snap-parallax-x-scope="none" data-snap-parallax-x-impulse="3">6</div>
</div>
<div class="slide">
<div class="wrap" data-snap-parallax-x="-50%" data-snap-parallax-x-scope="none" data-snap-parallax-x-impulse="3">7</div>
</div>
</div>
</div>
CSS
.carousel {
--size: clamp(max(10rem, 25vw), 50vh, 50vw);
position: relative;
width: 100%;
height: var(--size);
opacity: 0;
transition: opacity 0.25s linear;
}
.carousel.ready {
opacity: 1;
}
.slide {
position: absolute;
top: 0;
left: 0;
width: var(--size);
height: 100%;
}
.slide .wrap {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.08);
border-radius: 0.5rem;
font-size: 1rem;
font-weight: bold;
color: #ececec;
}
.slide:nth-child(1) .wrap {
background: var(--gradient-slide-1, #000);
}
.slide:nth-child(2) .wrap {
background: var(--gradient-slide-2, #000);
}
.slide:nth-child(3) .wrap {
background: var(--gradient-slide-3, #000);
}
.slide:nth-child(4) .wrap {
background: var(--gradient-slide-4, #000);
}
.slide:nth-child(5) .wrap {
background: var(--gradient-slide-5, #000);
}
.slide:nth-child(6) .wrap {
background: var(--gradient-slide-6, #000);
}
.slide:nth-child(7) .wrap {
background: var(--gradient-slide-7, #000);
}
JavaScript
import {
Snap
} from "vevet";
const container = document.getElementById("carousel");
const carousel = new Snap({
container,
origin: "center",
loop: true,
gap: "1.25rem",
lerp: 0.2,
freemode: true,
grabCursor: true
});
container.classList.add("ready");
carousel.on("update", () => {
carousel.slides.forEach(({
element,
coord,
isVisible
}) => {
element.style.transform = `translate(${coord}px, 0)`;
});
});
Parallax Effects
Each parallax attribute maps directly to a corresponding CSS transform (or opacity):
data-snap-parallax-x->translateX()data-snap-parallax-y->translateY()data-snap-parallax-z->translateZ()data-snap-parallax-scale->scale()- value is added to1data-snap-parallax-scale-x->scaleX()- value is added to1data-snap-parallax-scale-y->scaleY()- value is added to1data-snap-parallax-skew->skew()data-snap-parallax-skew-x->skewX()data-snap-parallax-skew-y->skewY()data-snap-parallax-rotate->rotate()data-snap-parallax-rotate-x->rotateX()data-snap-parallax-rotate-y->rotateY()data-snap-parallax-rotate-z->rotateZ()data-snap-parallax-opacity->opacity- should contain negative values only, decreasing the current opacity.
The value is added to the current opacity and clamped to [0, 1]
All effect attributes accept numbers or any supported CSS unit.
Parallax Timeline (scope)
By default, parallax values are applied while the slide transition progress is between -1 and 1.
You can inspect slide progress in this demo.
To change the active range, use the data-snap-parallax-scope attribute:
- numeric range like
data-snap-parallax-scope="-2, 2" - infinite range like
data-snap-parallax-scope="none"ordata-snap-parallax-scope="-Infinity, Infinity" - constant range like
data-snap-parallax-scope="const"data-snap-parallax-scope="1,1"; should be used withdata-snap-parallax-[effect]-impulse
The scope applies to all parallax effects inside a slide unless overridden per effect via data-snap-parallax-[effect]-scope:
<div class="slide">
<div
class="wrap"
data-snap-parallax-x="-200%"
data-snap-parallax-scope="-2, 2"
>
Slide Info
</div>
</div>
<!-- OR -->
<div class="slide">
<div
class="wrap"
data-snap-parallax-x="-200%"
data-snap-parallax-scale-scope="-2, 2"
>
Slide Info
</div>
</div>
Parallax Strength (impulse)
Use data-snap-parallax-[effect]-impulse to apply the effect only during dragging or wheeling.
The parallax value will smoothly increase or decrease based on interaction intensity, producing more "organic" motion.
<div class="slide">
<div
class="wrap"
data-snap-parallax-skew="-200"
data-snap-parallax-skew-scope="1,1"
data-snap-parallax-skew-impulse
>
Slide Info
</div>
</div>
Positive Values
data-snap-parallax-[effect]-abs forces the effect to use absolute (non-negative) values.
This is useful for properties like scale() where negative values are undesirable.
<div class="slide">
<div
class="wrap"
data-snap-parallax-scale="-0.5"
data-snap-parallax-scale-abs
>
Slide Info
</div>
</div>
Clamping (min-max)
data-snap-parallax-[effect]-minanddata-snap-parallax-[effect]-max` clamp the final computed parallax value, preventing it from going below or above the defined bounds:
<div class="slide">
<div
class="wrap"
data-snap-parallax-scale="-0.25"
data-snap-parallax-scale-scope="-2,2"
data-snap-parallax-scale-abs
data-snap-parallax-scale-min="0.5"
data-snap-parallax-scale-max="1"
data-snap-parallax-scale-impulse="3"
>
Slide Info
</div>
</div>
Value Offset
data-snap-parallax-[effect]-offset accepts a numeric value and forces a value offset for the active slide.
This might be useful for reverse animations.
<div class="slide">
<div
class="wrap"
data-snap-parallax-scale="0.5"
data-snap-parallax-scale-offset="-0.5"
data-snap-parallax-scale-scope="-2,2"
data-snap-parallax-scale-abs
>
Slide Info
</div>
</div>
Direction
data-snap-parallax-[effect]-directional adjusts the value’s sign automatically based on the scroll direction.
<div class="slide">
<div
class="wrap"
data-snap-parallax-skew="-200"
data-snap-parallax-skew-scope="1,1"
data-snap-parallax-skew-impulse
data-snap-parallax-skew-directional
>
Slide Info
</div>
</div>
Parallax example
Organic Gap
<div class="slide">
<div
class="wrap"
data-snap-parallax-x="-50%"
data-snap-parallax-x-scope="none"
data-snap-parallax-x-impulse="3"
>
Slide Info
</div>
</div>
Center Scale
<div class="slide">
<div
class="wrap"
data-snap-parallax-scale="-0.2"
data-snap-parallax-scale-scope="-1,1"
data-snap-parallax-scale-abs
>
Slide Info
</div>
</div>