Scrolltrigger , Elementor, GSAP
Create Horizontal Scroll Animation with staggered Text and parallax Image
SHARE
Elementor Pro Users
1. Setup of your Page in Elementor
Use this setup and the code if you don’t plan to have additional movement Scroll Triggers inside the Horizontal Scroll.
Copy this code in the Custom CSS
- Create a Scrollcontainer
- Flexbox, Full Width, Width 100%,
- Min Height 100vh
- Overflow: Hidden
- Margin 0, Padding 0
- CSS Classes: scroll-container
- Custom CSS for Elementor Pro –> Put this in your custom code or in the Advanced Tab in the Custom CSS
.scroll-container{
transition: none;
overscroll-behavior: none;
/* add the slash and star from code below in case all your settings are fine on mobile. this will overwrite all your settings in the editor*/
display:flex !important;
width:100% !important;
Height: 100vh !important;
overflow: hidden !important;
margin: 0px !important;
padding: 0px !important;
}
- Create a Scroll Content Container
- Flexbox, Full Width,
- Width auto ,
- Min Height 100vh
- Wrap: No Wrap, Gaps: 0, direction: Row Horizontal
- Margin 0, Padding 0
- CSS Classes: scroll-content
- Custom CSS for Elementor Pro –> Put this in your custom code or in the Advanced Tab in the Custom CSS
.scroll-content{
transition: none;
overscroll-behavior: none;
/* add the slash and star from code below in case all your settings are fine on mobile. this will overwrite all your settings in the editor*/
display:flex !important;
width: 400vw !important;
height: 100vh !important;
flex-wrap: nowrap !important;
gap: 0 !important;
flex-direction: row !important;
margin: 0 !important;
padding: 0 !important;
}
Panel Container CSS
Container Setup
- Desktop
- Flexbox, Full Width,
- Width 100vw,
- Min Height 100vh
- Direction: Row horizontal,
- Justify Content: Space Between
- Gaps: 5vw, 5vw
- HTML Tag: section (important because otherwise GSAP code is not working)
- Align Items: Center
- Style: Image Background, Center Center, Cover
- Background Overlay:
- Black,
- 0,6 Opacity
- Margin 0, Padding 10vw
- Size: Custom, Flex Grow 1, Flex Shrink 0. (important for horizontal scroll to work)
- CSS Classes: panel
- Tablet and Mobile (only values which will change)
- Direction: Column vertical
- Justify Content: Center
- Gaps: 2vw, 2vw
/* add the slash and star from code below in case all your settings are fine on mobile. this will overwrite all your settings in the editor*/
.panel {
display: flex !important;
width: 100vw !important;
height: 100vh !important;
flex-grow: 1 !important;
flex-shrink: 0 !important;
flex-basis: auto;
box-sizing: border-box !important;
}
Content Setup
Heading Container Panel 1
- Desktop
- Flexbox, Full Width,
- Width 70%
- Direction: Columns vertical,
- Tablet and mobile (only values which will change)
- Width: 100%
Heading Setup
- Desktop
- Text: Transform Your Online Presence with Stunning Web Design!, h2
- Style: Color: White
- Font: Family: Playfair Display, 5rem, weight: 600
- Margin Bottom: 24px
- Tablet and Mobile
- Font-Size Tablet : 3.5rem
- Font-Size Mobile: 2.5rem
- Class Name: text
Text Setup
- Text Setup Desktop
- Text: Scroll down to explore how we create impactful websites that not only look amazing but also perform exceptionally. Let’s start your journey to online success!
- Text Style: Color White, Font Family Roboto, Font-Size: 1.6rem
- CSS Class: text
- Text Setup Tablet and Mobile
- Font-Size Tablet: 1.4rem
- Font-Size Mobile: 1.2rem
Rotating Text Container
- Desktop:
- Flexbox, Full Width, Width 30%
- Min Height: 17vw
- Tablet and Mobile:
- Width: 100%
- Min Height Tablet : 25vw
- Min Height Mobile: 35vw
- Setup Rotating Text Circle (see my Video for it for details)
- Change Horizontal Orientation to End
- Icon Settings:
- Size Desktop: 5vw
- Size Tablet: 7vw
- Size Mobile: 8vw
- Class: Icon
Panel 2, 3 and 4 Container and Content
Panel Setup
- Panel Setup Desktop
- Flexbox, Full Width,
- Width 100vw,
- Min Height 100vh
- Direction: Row horizontal,
- Gaps: 0vw, 5vw
- HTML Tag: section (important because otherwise GSAP code is not working)
- Style: Background Color: black
- Margin left: -1,
- Padding 10vw
- Size: Custom, Flex Grow 1, Flex Shrink 0. (important for horizontal scroll to work)
- CSS Classes: panel
- Panel Setup Tablet and Mobile (only values which will change)
- Direction: Column vertical
- Justify Content: Center
- Gaps: 5vw, 5vw
Text Container
- Container Setup for Texts Desktop
- Flexbox, Full width, Width 60%
- Justify Content: Center
- Direction: Column Vertical
- Align Items: Left
- Gaps: 0
- Margin: 0
- Padding: 0
- CSS Class: container
- Container Setup Tablet and Mobile
- Width: 100%
Hiding Container for Texts
- Number Container
- Flexbox, Full width, Width 100%
- Overflow Hidden (for stagger effect)
- Padding Bottom: 10px
Copy This container twice for efficiency 🙂
- Container Staggered Heading
- Margin Desktop Bottom: 20
- Padding Desktop Bottom: 20
- Margin Tablet Bottom: 16
- Padding Tablet Bottom: 16
- Margin Mobile Bottom: 12
- Padding Mobile Bottom: 12
- Text Editor Widget Container:
- nothing to add
Text Setup
- Heading Number Setup
- Content: 01
- Text Color: White
- Font-Family: Playfair Display
- Font-Size Desktop: 3rem
- Font-Size Tablet: 2.4rem
- Font-Size Mobile: 1.6rem
- CSS Class: text
- Staggered Text:
- Content: Custom<br> Webdesign
- Text-Color: White
- Font-Family: Playfair Display
- Font-Size Desktop: 6rem
- Font-Size Tablet: 4.5rem
- Font-Size Mobile: 2.5
- CSS Class: text
- Texteditor Setting:
- Content:
- We craft stunning websites that reflect your unique brand identity. Whether you need a fresh redesign or a brand-new site, we’ve got you covered.
- Font Family: Roboto
- Fontsize Desktop: 1.6
- Fontsize Tablet: 1.4
- Fontsize Mobile: 1.1
- CSS Class: text-two
- Content:
Image Container
- Container Desktop
- Flexbox, Full Width, Width 40%
- Justify Content: Bottom
- Container Tablet and Mobile
- Width: 100%
- Image Desktop
- Add an Image
- Style: Width: 100% (can also be less)
- CSS Class: img
- Image Tablet and Mobile
- Tablet Width: 50%
- Alignement: Left
- Mobile Width: 60%
Copy this Panel two times.
Add HTML Widget and Paste the Code in from below.
- Container Desktop
Copy the just Created Panel two times and fill in your individual content for each panel
GSAP Code for your HTML Widget
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/split-type@0.3.4/umd/index.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
gsap.registerPlugin(ScrollTrigger);
let container = document.querySelector(".scroll-content");
let scrollContainer = document.querySelector(".scroll-container");
if (!container || !scrollContainer) {
console.error("Container oder Scroll-Container nicht gefunden. Überprüfe die Klassennamen.");
return;
}
// Timeline for horizontal scrolling and parallax effects
let scrollTimeline = gsap.timeline({
scrollTrigger: {
trigger: scrollContainer,
pin: true,
scrub: 1,
start: "top top",
end: () => "+=" + container.scrollWidth,
markers: false,
invalidateOnRefresh: true,
},
});
// Add Horizontal Scroll to Timeline
scrollTimeline.to(container, {
x: () => -(container.scrollWidth - window.innerWidth),
ease: "none",
});
// Zerlege den Text in Buchstaben
document.querySelectorAll(".panel .text").forEach((textElement) => {
new SplitType(textElement, { types: "chars" });
});
// Animieren der Buchstaben in jedem Panel
document.querySelectorAll(".panel").forEach((panel) => {
const chars = panel.querySelectorAll(".char"); // Buchstaben des Panels auswählen
if (chars.length > 0) {
gsap.from(chars, {
y: 200,
opacity: 1,
duration: 2,
ease: "power1.out",
stagger: 0.05, // Verzögerung zwischen Buchstaben
scrollTrigger: {
containerAnimation: scrollTimeline, // Verknüpfe mit horizontalem Scroll
trigger: panel,
start: "left 60%",
end: "left 30%",
scrub: true,
markers: false,
},
});
}
});
// Animieren der Bilder in jedem Panel
const panels = gsap.utils.toArray(".panel");
panels.forEach((section, index) => {
const images = section.querySelectorAll(".img");
if (images.length > 0) {
images.forEach((image) => {
if (index === panels.length - 1) {
gsap.from(image, {
x: "+0",
opacity: 0.5,
scale: 0.5,
ease: "power2.out",
scrollTrigger: {
containerAnimation: scrollTimeline,
trigger: image,
start: "left 100%",
end: "left 50%",
scrub: true,
invalidateOnRefresh: true,
markers: false /*{
startColor: "green",
endColor: "orange",
fontSize: "14px",
indent: 20,
},*/
},
});
} else {
gsap.from(image, {
x: +200,
opacity: 0.5,
scale: 0.5,
scrollTrigger: {
containerAnimation: scrollTimeline,
trigger: image,
start: "left 100%",
end: "left 0%",
scrub: 1,
invalidateOnRefresh: true,
markers: false /*{
startColor: "blue",
endColor: "red",
fontSize: "12px",
indent: 20,
},*/
},
});
}
});
} else {
console.warn("Keine Bilder gefunden in:", section);
}
});
// Animation für alle Elemente mit der Klasse "text-two"
document.querySelectorAll(".text-two").forEach((textElement) => {
gsap.from(textElement, {
opacity: 0,
duration: 1,
ease: "power1.out",
scrollTrigger: {
containerAnimation: scrollTimeline,
trigger: textElement,
invalidateOnRefresh: true,
start: "left 70%",
end: "left 60%",
scrub: true,
markers: false /*{
startColor: "purple",
endColor: "yellow",
fontSize: "20px",
},*/
},
});
});
// Animation für das Icon
gsap.from(".icon", {
rotation: -90,
duration: 1,
scrollTrigger: {
containerAnimation: scrollTimeline,
trigger: ".icon",
start: "left 50%",
end: "left 40%",
scrub: 1,
invalidateOnRefresh: true,
markers: false /*{
startColor: "yellow",
endColor: "green",
fontSize: "25px",
},*/
},
});
// ScrollTrigger.refresh() bei Resize
window.addEventListener("resize", () => {
ScrollTrigger.refresh(); // Sicherheitsmaßnahme, um Positionen neu zu berechnen
});
});
</script>
Elementor Free Users:
Paste this into your HTML Widget. CSS Code is already included.
<style>
.scroll-container{
transition: none;
overscroll-behavior: none;
/* add the slash and star from code below in case all your settings are fine on mobile. this will overwrite all your settings in the editor*/
display:flex !important;
width:100% !important;
Height: 100vh !important;
overflow: hidden !important;
margin: 0px !important;
padding: 0px !important;
}
.scroll-content{
transition: none;
overscroll-behavior: none;
/* add the slash and star from code below in case all your settings are fine on mobile. this will overwrite all your settings in the editor*/
display:flex !important;
width: 400vw !important;
height: 100vh !important;
flex-wrap: nowrap !important;
gap: 0 !important;
flex-direction: row !important;
margin: 0 !important;
padding: 0 !important;
}
/* add the slash and star from code below in case all your settings are fine on mobile. this will overwrite all your settings in the editor*/
.panel {
display: flex !important;
width: 100vw !important;
height: 100vh !important;
flex-grow: 1 !important;
flex-shrink: 0 !important;
flex-basis: auto;
box-sizing: border-box !important;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/split-type@0.3.4/umd/index.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
gsap.registerPlugin(ScrollTrigger);
let container = document.querySelector(".scroll-content");
let scrollContainer = document.querySelector(".scroll-container");
if (!container || !scrollContainer) {
console.error("Container oder Scroll-Container nicht gefunden. Überprüfe die Klassennamen.");
return;
}
// Timeline for horizontal scrolling and parallax effects
let scrollTimeline = gsap.timeline({
scrollTrigger: {
trigger: scrollContainer,
pin: true,
scrub: 1,
start: "top top",
end: () => "+=" + container.scrollWidth,
markers: false,
invalidateOnRefresh: true,
},
});
// Add Horizontal Scroll to Timeline
scrollTimeline.to(container, {
x: () => -(container.scrollWidth - window.innerWidth),
ease: "none",
});
// Zerlege den Text in Buchstaben
document.querySelectorAll(".panel .text").forEach((textElement) => {
new SplitType(textElement, { types: "chars" });
});
// Animieren der Buchstaben in jedem Panel
document.querySelectorAll(".panel").forEach((panel) => {
const chars = panel.querySelectorAll(".char"); // Buchstaben des Panels auswählen
if (chars.length > 0) {
gsap.from(chars, {
y: 200,
opacity: 1,
duration: 2,
ease: "power1.out",
stagger: 0.05, // Verzögerung zwischen Buchstaben
scrollTrigger: {
containerAnimation: scrollTimeline, // Verknüpfe mit horizontalem Scroll
trigger: panel,
start: "left 60%",
end: "left 30%",
scrub: true,
markers: false,
},
});
}
});
// Animieren der Bilder in jedem Panel
const panels = gsap.utils.toArray(".panel");
panels.forEach((section, index) => {
const images = section.querySelectorAll(".img");
if (images.length > 0) {
images.forEach((image) => {
if (index === panels.length - 1) {
gsap.from(image, {
x: "+0",
opacity: 0.5,
scale: 0.5,
ease: "power2.out",
scrollTrigger: {
containerAnimation: scrollTimeline,
trigger: image,
start: "left 100%",
end: "left 50%",
scrub: true,
invalidateOnRefresh: true,
markers: false /*{
startColor: "green",
endColor: "orange",
fontSize: "14px",
indent: 20,
},*/
},
});
} else {
gsap.from(image, {
x: +200,
opacity: 0.5,
scale: 0.5,
scrollTrigger: {
containerAnimation: scrollTimeline,
trigger: image,
start: "left 100%",
end: "left 0%",
scrub: 1,
invalidateOnRefresh: true,
markers: false /*{
startColor: "blue",
endColor: "red",
fontSize: "12px",
indent: 20,
},*/
},
});
}
});
} else {
console.warn("Keine Bilder gefunden in:", section);
}
});
// Animation für alle Elemente mit der Klasse "text-two"
document.querySelectorAll(".text-two").forEach((textElement) => {
gsap.from(textElement, {
opacity: 0,
duration: 1,
ease: "power1.out",
scrollTrigger: {
containerAnimation: scrollTimeline,
trigger: textElement,
invalidateOnRefresh: true,
start: "left 70%",
end: "left 60%",
scrub: true,
markers: false /*{
startColor: "purple",
endColor: "yellow",
fontSize: "20px",
},*/
},
});
});
// Animation für das Icon
gsap.from(".icon", {
rotation: -90,
duration: 1,
scrollTrigger: {
containerAnimation: scrollTimeline,
trigger: ".icon",
start: "left 50%",
end: "left 40%",
scrub: 1,
invalidateOnRefresh: true,
markers: false /*{
startColor: "yellow",
endColor: "green",
fontSize: "25px",
},*/
},
});
// ScrollTrigger.refresh() bei Resize
window.addEventListener("resize", () => {
ScrollTrigger.refresh(); // Sicherheitsmaßnahme, um Positionen neu zu berechnen
});
});
</script>