Hi !
On my portfolio website that I'm building with Nuxt.js, I want that when the user clicks on a project, the page is scrolled until the top of the project image is aligned with the word "Réalisations" - about 250px from the top of the page.
I was inspired by this official gsap example : https://codepen.io/GreenSock/pen/LZOMKY
As you can see on my website , when you click on the image and the content is scrolled up, the image does not stop at the right place - but in the opposite direction it works correctly.... any idea what may cause this issue ?
Thank you for your help !
ScrollTo script triggered when the user click on a project :
scrollToRealisation(event) {
let target = event.target.closest(".realisation")
this.$gsap.to(window, {duration: 0.5, scrollTo: {y: target, offsetY:250}});
},
Here is the whole code of the page component :
<template>
<div id="realisations">
<div v-for="item in orderRealisations" :key="item.titre" class="realisation">
<figure @click="scrollToRealisation($event)">
<img :src="require('/assets/imgs/projets/'+item.img)" :alt="item.titre">
</figure>
<div class="content">
<div class="contentWrapper">
<header>
<h3>{{ item.titre }}</h3>
<h5 class="client-year">{{ item.client }} - {{ item.annee }}</h5>
</header>
<p class="description">
{{ item.description }}
</p>
<footer>
<a class="projectLink" :href="item.url" target="_blank">Consulter le site</a>
</footer>
</div>
</div>
</div>
</div>
</template>
<script>
import realisationData from '~/static/data.json'
export default {
name: 'realisations',
data() {
return {
sections: []
}
},
asyncData ({ params }) {
return { realisationData }
},
mounted() {
this.sections = this.$gsap.utils.toArray('.realisation');
this.animateOnScroll()
},
computed: {
orderRealisations() {
return this.realisationData.sort((a, b) => b.annee.localeCompare(a.annee));
}
},
methods: {
//ScrollTo
scrollToRealisation(event) {
let target = event.target.closest(".realisation")
this.$gsap.to(window, {duration: 0.5, scrollTo: {y: target, offsetY:250}});
},
animateOnScroll() {
const gsap = this.$gsap
this.sections.forEach((section) => {
let image = section.getElementsByTagName('figure')
let content = section.getElementsByClassName('contentWrapper')
this.$ScrollTrigger.saveStyles(".realisation figure, .realisation .contentWrapper");
this.$ScrollTrigger.matchMedia({
"(min-width: 769px)": function() {
let imageTl = gsap .timeline({
scrollTrigger: {
trigger: section,
start: 'top 60%',
scrub: 2,
end: 'bottom 0px',
}
})
imageTl.addLabel("animationstart")
.to(image, {width: '30vw'})
.to(image, {width: '20vw'})
let contentTl = gsap.timeline({
scrollTrigger: {
trigger: section,
start: 'top 40%',
scrub: false,
//in: true,
//markers: true,
end: 'bottom 35%',
toggleActions: "play reverse play reverse"
}
})
contentTl.addLabel("contentanimation")
.fromTo(content, {x:-300, opacity:0,}, {x:0, opacity:1 }, '-=0.8')
},
// mobile
"(max-width: 768px)": function() {
let contentMobileTl = gsap.timeline({
scrollTrigger: {
trigger: section,
start: 'top 40%',
scrub: false,
//markers: true,
end: 'bottom 35%',
toggleActions: "play reverse play reverse"
}
})
contentMobileTl.addLabel("contentanimation")
.fromTo(content, {y:-200, marginTop: 0, height: 0, opacity:0,}, {y:0, height: 'auto',marginTop: 20, marginBottom: 40, opacity:1 }, '-=0.8')
}
})
})
}
}
}
</script>
<style lang="scss">
#realisations {
padding-bottom: 60vh;
padding-top: 225px;
@media all and (max-width: 768px) {
padding-top: 0;
}
.realisation {
display: flex;
margin-bottom: 3em;
@media all and (max-width: 768px) {
display: block;
flex-direction: column;
margin-bottom: 1em;
}
figure {
margin: 0;
width: 20vw;
cursor: pointer;
img {
width: 100%;
box-shadow: rgba(255, 255, 255, 0.1) 0px 1px 1px 0px inset, rgba(50, 50, 93, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px;
}
@media all and (max-width: 768px) {
width: 100%;
}
}
.content {
max-width: 500px;
overflow:hidden;
margin-left: 40px;
@media all and (max-width: 768px) {
margin-left: 0;
height: auto;
}
}
.contentWrapper {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
flex-wrap: wrap;
header {
h3, h5 {
margin: 0;
}
h3 {
font-size: 1.4em;
margin-bottom: 0em;
@media all and (max-width: 768px) {
font-size: 1em;
}
}
h5 {
font-weight: 400;
}
}
p {
font-size: 0.9em;
line-height: 1.2;
}
footer {
// margin-top: auto;
a {
color: #fff;
text-decoration: underline;
font-size: 0.7em;
}
}
}
}
}
</style>