0

I'm trying to create a diagonal gallery that moves with scroll, but when I scroll too fast the sliders (pictures) don't return to their positions, I tried to solve this problem, but it doesn't look good, the pictures have to return to a position when I scroll up or down without getting disordered.

examples: https://www.env.studio/ https://3rcore.com/

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="styles.css">
    <title>Locomotive scrolling</title>
</head>
<body>


    <div class="container">

        <div class="container__gallery">

            <div class="slide__1">
                <div class="img1">
                </div>
                <div class="img2">
                </div>
                <div class="img3">
                </div>
                <div class="img4">
                </div>
            </div>
            <div class="slide__2">
                <div class="img2"></div>
                <div class="img4">
                </div>
                <div class="img1">
                </div>
                <div class="img3">
                </div>
            </div>
            <div class="slide__3">
                <div class="img1">
                </div>
                <div class="img3">
                </div>
                <div class="img2">
                </div>
                <div class="img4">
                </div>
            </div>
            <div class="slide__4">
                <div class="img4">
                </div>
                <div class="img1">
                </div>

                <div class="img2">
                </div>
                <div class="img3">
                </div>
            </div>

        </div>

    </div>
</body>
<script src="main.js"></script>

</html>
*{
    margin: 0;
    padding: 0;
}

.container{
    background-color: white;
    width: 100%;
    height: 800px;
    margin-top: 1000px;
    margin-bottom: 1000px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.container__gallery{
    position: relative;
    background-color: white;
    width: 70%;
    height: 80%;
    overflow: hidden;
    border-radius: 8px;
}


.slide__1, .slide__2, .slide__3, .slide__4{
    position: absolute;
    background-color: white;
    width: 140%;
    height: 40%;
    display: flex;
    margin-bottom: 5px;
    transform: skew(-10deg) rotateZ(20deg);
}

.slide__1{
    top: -37px;
    right: -830px;
    transition: all 50ms ease-in;
}

.slide__2{
    top: 10px;
    right: -190px;
    transition: all 50ms ease-in;
}

.slide__3{
    top: 400px;
    right: -430px;
    transition: all 50ms ease-in;
}

.slide__4{
    top: 568px;
    right: -100px;
    transition: all 50ms ease-in;
}

.img1{
    background-color: blueviolet;
    background-image: url("https://static.fundacion-affinity.org/cdn/farfuture/PVbbIC-0M9y4fPbbCsdvAD8bcjjtbFc0NSP3lRwlWcE/mtime:1643275542/sites/default/files/los-10-sonidos-principales-del-perro.jpg");
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    height: 100%;
    width: 25%;
    margin-right: 5px;
}
.img2{
    background-color: orange;
    background-image: url("https://media.glamour.mx/photos/6529b544daab1b14402e2b34/16:9/w_2992,h_1683,c_limit/qu%C3%A9-significa-encontrarte-con-un-gato-negro-en-viernes-13-.png");
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    height: 100%;
    width: 25%;
    margin-right: 5px;
}
.img3{
    background-color: crimson;
    background-image: url("https://ca-times.brightspotcdn.com/dims4/default/796e6c9/2147483647/strip/true/crop/1970x1108+39+0/resize/1200x675!/quality/75/?url=https%3A%2F%2Fcalifornia-times-brightspot.s3.amazonaws.com%2F12%2Fa5%2F79e097ccf62312d18a025f22ce48%2Fhoyla-recuento-11-cosas-aman-gatos-top-001");
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    height: 100%;
    width: 25%;
    margin-right: 5px;
}
.img4{
    background-color: black;
    background-image: url("https://www.ngenespanol.com/wp-content/uploads/2023/12/descubren-que-los-humanos-influimos-en-el-color-de-ojos-de-los-perros-1280x720.jpg");
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    height: 100%;
    width: 25%;
    margin-right: 5px;
}


const element = document.querySelector('.container__gallery')
const slider1 = document.querySelector('.slide__1')
const slider2 = document.querySelector('.slide__2')
const slider3 = document.querySelector('.slide__3')
const slider4 = document.querySelector('.slide__4')

let lastScrollTop = 0

let control = {
    top1: -37,
    right1: -830,
    top2: 10,
    right2: -190,
    top3: 400,
    right3: -430,
    top4: 350,
    right4: 460,
}

const options = {
    root: null,
    rootMargin: '600px',
    threshold: 0.05
}

const observer = new IntersectionObserver(callback, options)
observer.observe(element)

function validateScrolling(){

    const currentScrollTop = window.pageYOffset || document.documentElement.scrollTop;
    const isScrollingDown = currentScrollTop > lastScrollTop;
    lastScrollTop = currentScrollTop;
    return isScrollingDown;
}

function move(isScrollingDown){
    // Definir el ángulo en radianes (20 grados)
    const anguloRadianes = 158.72 * (Math.PI / 180);
    const scale = 0.01;
    let deltaX = 0
    let deltaY = 0
    const scrollY = window.scrollY || window.pageYOffset;

    if(!(isScrollingDown ===false && scrollY <= 200 && scrollY >= 122))
        // Calcular el cambio en las coordenadas X e Y utilizando funciones trigonométricas
        deltaX = scrollY * Math.cos(anguloRadianes) * scale;
        deltaY = scrollY * Math.sin(anguloRadianes) * scale;



    return {deltaX, deltaY}
}

function scrollerEvent(){

    let isScrollingDown = validateScrolling()
    let delta = move(isScrollingDown)

    if(isScrollingDown == false && scrollY <= 200 && scrollY >= 120){

        control.right1 = -830;
        control.top1 = -37;

        control.right2 = -190;
        control.top2 = 10;

        control.right3 = -430 ;
        control.top3 = 400 ;

        control.right4 = 460;
        control.top4 = 350;

        slider1.style.right = control.right1 + "px";
        slider1.style.top = control.top1 + "px";

        slider2.style.right = control.right2 + "px";
        slider2.style.top = control.top2 + "px";

        slider3.style.right = control.right3 + "px";
        slider3.style.top = control.top3 + "px";

        slider4.style.right = control.right4 + "px";
        slider4.style.top = control.top4 + "px";
    }
    else if(isScrollingDown == false && scrollY <= 1000 && scrollY >= 977){

        control.right1 = -537.9142029413038  ;
        control.top1 = -150.7620539573103;

        control.right2 = -482.0857970586964  ;
        control.top2 = 123.7620539573103;

        control.right3 = -225.5399420589124  ;
        control.top3 = 320.36656222988285 ;

        control.right4 = 167.91420294130347;
        control.top4 = 463.76205395731006;


        slider1.style.transition = "600ms"
        slider1.style.right = control.right1 + "px";
        slider1.style.top = control.top1 + "px";
        //slider1.style.transition = "50ms"

        slider2.style.transition = "600ms"
        slider2.style.right = control.right2 + "px";
        slider2.style.top = control.top2 + "px";
        //slider2.style.transition = "50ms"

        slider3.style.transition = "600ms"
        slider3.style.right = control.right3 + "px";
        slider3.style.top = control.top3 + "px";

        slider4.style.transition = "600ms"
        slider4.style.right = control.right4 + "px";
        slider4.style.top = control.top4 + "px";
        //slider4.style.transition = "50ms"
    }
    else if (isScrollingDown){
        // Actualizar las coordenadas del objeto
        control.right1 -= delta.deltaX;
        control.top1 -= delta.deltaY;

        control.right2 += delta.deltaX;
        control.top2 += delta.deltaY;

        control.right3 -= (delta.deltaX * 0.7);
        control.top3 -= (delta.deltaY * 0.7);

        control.right4 += delta.deltaX;
        control.top4 += delta.deltaY;

        slider1.style.transition = "50ms"
        slider1.style.right = control.right1 + "px";
        slider1.style.top = control.top1 + "px";

        slider2.style.transition = "50ms"
        slider2.style.right = control.right2 + "px";
        slider2.style.top = control.top2 + "px";

        slider3.style.transition = "50ms"
        slider3.style.right = control.right3 + "px";
        slider3.style.top = control.top3 + "px";

        slider4.style.transition = "50ms"
        slider4.style.right = control.right4 + "px";
        slider4.style.top = control.top4 + "px";
    }
    else{
        // Actualizar las coordenadas del objeto

        control.right1 += delta.deltaX;
        control.top1 += delta.deltaY;

        control.right2 -= delta.deltaX;
        control.top2 -= delta.deltaY;

        control.right3 += (delta.deltaX *0.7);
        control.top3 += (delta.deltaY *0.7);

        control.right4 -= delta.deltaX;
        control.top4 -= delta.deltaY;


        slider1.style.transition = "50ms"
        slider1.style.right = control.right1 + "px";
        slider1.style.top = control.top1 + "px";

        slider2.style.transition = "50ms"
        slider2.style.right = control.right2 + "px";
        slider2.style.top = control.top2 + "px";

        slider3.style.transition = "50ms"
        slider3.style.right = control.right3 + "px";
        slider3.style.top = control.top3 + "px";

        slider4.style.transition = "50ms"
        slider4.style.right = control.right4 + "px";
        slider4.style.top = control.top4 + "px";
    }
}

function callback(entries){

    entries.forEach(entry =>{
        let intersecting = entry.isIntersecting
        if (intersecting){
            lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;
            window.addEventListener("scroll", scrollerEvent)
        }
        else{
            window.removeEventListener("scroll", scrollerEvent);
        }
    })
}

1 Answer 1

0

You can achieve this with a lot less code :) here is a jsfiddle doing something similar https://jsfiddle.net/ash_uncover/62tmbdp7/69/

The idea is to first display the 'slides' normally and play on rotate & scale transformations with simple values rather than using complex calculations :)

const container = document.getElementById('container');
const slide1 = document.getElementById('slide1');
const slide2 = document.getElementById('slide2');
const slide3 = document.getElementById('slide3');
const slide4 = document.getElementById('slide4');

window.addEventListener('scroll', (event) => {
  const force = container.parentElement.scrollTop / container.offsetHeight * 20
  
  slide1.style.translate = `${force}%`
  slide2.style.translate = -`${force}%`
  slide3.style.translate = `${force}%`
  slide4.style.translate = -`${force}%`
}, true)
html, body {
  margin: 0;
  height: 100%;
  overflow: auto;
}

.container{
  background-color: white;
  width: 100%;
}

.content {
  height: 300px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 64px;
}

.gallery {
  position: relative;
  width: 100%;
  height: 300px;
  overflow: hidden;
  display: flex;
  align-items: center;
}

.gallery-container {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: center;
  justify-content: center;
  rotate: 45deg;
}

.slide {
  width: 100%;
  display: flex;
  gap: 2px;
}

.img {
  width: 0;
  flex-grow: 1;
  aspect-ratio: 1;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.img1{
    background-image: url("https://static.fundacion-affinity.org/cdn/farfuture/PVbbIC-0M9y4fPbbCsdvAD8bcjjtbFc0NSP3lRwlWcE/mtime:1643275542/sites/default/files/los-10-sonidos-principales-del-perro.jpg");
}
.img2{
    background-image: url("https://media.glamour.mx/photos/6529b544daab1b14402e2b34/16:9/w_2992,h_1683,c_limit/qu%C3%A9-significa-encontrarte-con-un-gato-negro-en-viernes-13-.png");
}
.img3{
    background-image: url("https://ca-times.brightspotcdn.com/dims4/default/796e6c9/2147483647/strip/true/crop/1970x1108+39+0/resize/1200x675!/quality/    75/?url=https%3A%2F%2Fcalifornia-times-brightspot.s3.amazonaws.com%2F12%2Fa5%2F79e097ccf62312d18a025f22ce48%2Fhoyla-recuento-11-cosas-aman-gatos-top-001");
}
.img4{
    background-image: url("https://www.ngenespanol.com/wp-content/uploads/2023/12/descubren-que-los-humanos-influimos-en-el-color-de-ojos-de-los-perros-1280x720.jpg");    
}
<div id="container" class="container">

  <div class="content">
    Hello scroll (top)
  </div>

  <div class="gallery">
    <div class="gallery-container">
      <div id="slide1" class="slide">
        <div class="img img1"></div>
        <div class="img img2"></div>
        <div class="img img3"></div>
        <div class="img img4"></div>
      </div>
      <div id="slide2" class="slide">
        <div class="img img2"></div>
        <div class="img img4"></div>
        <div class="img img1"></div>
        <div class="img img3"></div>
      </div>
      <div id="slide3" class="slide">
        <div class="img img1"></div>
        <div class="img img3"></div>
        <div class="img img2"></div>
        <div class="img img4"></div>  
      </div>
      <div id="slide4" class="slide">
        <div class="img img4"></div>  
        <div class="img img1"></div>
        <div class="img img3"></div>
        <div class="img img2"></div>
      </div>
    </div>
  </div>
  
  <div class="content">
    Hello scroll (bottom)
  </div>
  
</div>

You can play around with the rotation (set to 45deg here) and the way the 'force' variable is computed to obtain variations of the effect.

Not the answer you're looking for? Browse other questions tagged or ask your own question.