Горизонтальная анимация при вертикальной прокрутке

Есть изображение вагона поезда. Хочу сделать эффект бесконечного движения вагонов слева направо при прокрутке страницы вниз. Этот поезд будет размещён в фиксированном блоке, прилипшем к низу браузера. Посоветуйте пожалуйста, как лучше сделать этот эффект анимации, и как его связать с прокруткой? Спасибо.


Ответы (1 шт):

Автор решения: Vladislav G.

Как-то так

const trainOptions = {
    width: 300,
    space: 20,
    speed: 0.2,
    scrollTrigger: null
};

function initTarin (container, template) {
    container.innerHTML = '';
    const count = Math.ceil(container.offsetWidth / trainOptions.width) + 2;

    for (let i = 0; i < count; i++) {
        container.append(template.cloneNode(true));
    }

    container.scrollLeft = trainOptions.width + trainOptions.space;
    trainOptions.scrollTrigger = trainOptions.width;
}

function checkScroll (container, template, sign) {
    if (sign && container.scrollLeft <= trainOptions.scrollTrigger) {
        container.prepend(template.cloneNode(true));
        container.children[container.children.length - 1].remove();
        container.scrollLeft = trainOptions.scrollTrigger * 2 + trainOptions.space;
    }
    else if (!sign && container.scrollLeft >= container.scrollWidth - container.offsetWidth - trainOptions.scrollTrigger) {
        container.append(template.cloneNode(true));
        container.children[0].remove();
        container.scrollLeft = container.scrollWidth - container.offsetWidth - trainOptions.scrollTrigger * 2 - trainOptions.space;
    }
}

function initContent (container) {
    for (let i = 0; i < 20; i++) {
        const content = document.createElement('p');
        content.textContent = 'много какого то контента';
        content.classList.add('content');
        container.append(content);
    }
}

(function app () {
    const page = document.body;
    const trainContainer = document.querySelector('.train-container');
    const trainTemplate = document.querySelector('#train-template').content.querySelector('.train');

    initContent(page);
    initTarin(trainContainer, trainTemplate);

    page.addEventListener('wheel', evt => {
        trainContainer.scrollLeft += -evt.deltaY * trainOptions.speed;
        const sign = evt.deltaY > 0 ? true : false;
        checkScroll(trainContainer, trainTemplate, sign);
    });

    new ResizeObserver(() => {
        initTarin(trainContainer, trainTemplate);
    }).observe(trainContainer);
})();
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

.page {
    background-color: #333;
}

.content {
    margin: 20px auto;
    padding: 200px 0;
    width: 50%;

    background-color: rgba(80, 80, 100, 0.5);
    border-radius: 20px;

    color: #fff;
    text-align: center;
}

.train-container {
    position: fixed;
    bottom: 0;

    display: flex;
    flex-direction: row;
    align-items: center;

    width: 100%;
    height: 200px;

    background-color: #222;

    overflow: hidden;
    z-index: -1;
}

.train {
    display: flex;
    flex-direction: row;
    justify-content: space-evenly;


    margin-left: 20px;
    padding-top: 20px;
    min-width: 300px;
    height: 50%;

    border-radius: 8px;
    background-color: #575;
}

.window {
    width: 30px;
    height: 30px;

    border-radius: 6px;
    background-color: #ddf;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body class="page">
    <div class="train-container"></div>
    <template id="train-template">
        <div class="train">
            <div class="window"></div>
            <div class="window"></div>
            <div class="window"></div>
            <div class="window"></div>
            <div class="window"></div>
        </div>
    </template>
    <script src="main.js"></script>
</body>

</html>

→ Ссылка