为什么我的无限选取框动画重启时不稳定,而不是平滑循环?

问题描述 投票:0回答:1

我的无限选取框动画遇到问题。每当到达终点时,它都不会平滑地过渡回起点,而是突然重新开始。

    const scrollers = document.querySelectorAll(".services-brand");

    if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
        addScrolling();
    }

    function addScrolling() {
        scrollers.forEach((scroller) => {
            scroller.setAttribute("data-animated", true);

            const scrollerInner = scroller.querySelector('.scroller__inner')
            const scrollerContent = Array.from(scrollerInner.children);

            scrollerContent.forEach((item) => {
                const duplicatedItem = item.cloneNode(true);
                duplicatedItem.setAttribute("aria-hidden", true);
                scrollerInner.appendChild(duplicatedItem);
            })
        });
    }
section.services-brand {
    width: 100%;
    background: white;
    position: relative;
    margin-top: -100px;
}
.services-brand[data-animated="true"] {
    overflow: hidden;
}
.services-brand[data-animated="true"] .s-brand-wrapper {
    flex-wrap: nowrap;
}
.s-brand-wrapper {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    padding: 20px 0px;
    animation: brandScroller 5s linear infinite;
}
.s-brand-block span {
    font-size: 20px;
    font-family: var(--main-hard-font);
    font-weight: 800;
    color: var(--black-main-clr);
}

@keyframes brandScroller {
    0% {
        transform: translateX(0%);
    }
    100% {
        transform: translateX(-100%);
    }
}

.s-brand-block {
    display: flex;
    align-items: center;
    gap: 5px;
    justify-content: center;
    min-width: fit-content;
    margin-right: 50px;
    padding-right: 10px;
}

.s-brand-block img {
    height: 50px;
}
<section class="services-brand">
        <div class="s-brand-wrapper scroller__inner">
            <div class="s-brand-block">
                <img src="{{ asset('images/3d-icons/web-development.png') }}" alt="web development">
                <span>Web Development</span>
            </div>
            <div class="s-brand-block">
                <img src="{{ asset('images/3d-icons/marketing.png') }}" alt="Digital Marketing">
                <span>Digital Marketing</span>
            </div>
            <div class="s-brand-block">
                <img src="{{ asset('images/3d-icons/content-creation.png') }}" alt="Content Creation">
                <span>Content Creation</span>
            </div>
            <div class="s-brand-block">
                <img src="{{ asset('images/3d-icons/design.png') }}" alt="Design/Brending">
                <span>Design/Brending</span>
            </div>
            <div class="s-brand-block">
                <img src="{{ asset('images/3d-icons/seo.png') }}" alt="Seo">
                <span>SEO</span>
            </div>
            <div class="s-brand-block">
                <img src="{{ asset('images/3d-icons/ux-ui.png') }}" alt="UX/UI">
                <span>UX/UI</span>
            </div>
        </div>
    </section>

我尝试调整动画属性,例如

animation-direction
,以在选取框动画的结束和开始之间创建更平滑的过渡。然而,尽管我做出了努力,动画仍然突然重新启动,没有达到预期的无缝循环。

javascript css loops animation marquee
1个回答
0
投票

添加的

s-brand-block
并不完全是
s-brand-wrapper
宽度的两倍(我不明白为什么) - 您可以通过添加添加的 div 的宽度,然后计算动画结束的百分比来解决这个问题翻译值 - 我为此使用了一个名为
--perc
的 CSS 变量

但是,您必须等待图像加载后才能执行此操作。另外,执行此计算时需要考虑右边距

注意:我根据 Mehdi 对您问题的编辑使用了外部图像(尽管他的编辑已损坏)

另请注意

margin-top:-100px
阻止输出在代码片段中可见

const scrollers = document.querySelectorAll(".services-brand");

if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
  addScrolling();
}
function imagePromise(item) {
  const img = item.querySelector('img')
  return new Promise((resolve, reject) => {
    img.addEventListener('load', () => resolve(item.getBoundingClientRect().width));
    img.addEventListener('error', reject);
  });
}
function addScrolling() {
    scrollers.forEach((scroller) => {
        scroller.setAttribute("data-animated", true);
        const scrollerInner = scroller.querySelector('.scroller__inner')
        const scrollerContent = Array.from(scrollerInner.children);
        const promises = scrollerContent.map((item) => {
            const duplicatedItem = item.cloneNode(true);
            duplicatedItem.setAttribute("aria-hidden", true);
            scrollerInner.appendChild(duplicatedItem);
            return imagePromise(duplicatedItem);
        });
        Promise.all(promises).then((v) => {
          // the `50` below is your margin-right in .s-brand-block
          const tot = v.reduce((acc, width) => acc + width + 50, 0);
          const perc = tot/scrollerInner.getBoundingClientRect().width * 100;
          scroller.style.setProperty("--perc", `-${perc}%`);
        })
    });
}
section.services-brand {
    width: 100%;
    background: white;
    position: relative;
    margin-top: 0px;
}
.services-brand[data-animated="true"] {
    overflow: hidden;
}
.services-brand[data-animated="true"] .s-brand-wrapper {
    flex-wrap: nowrap;
}
.s-brand-wrapper {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    padding: 20px 0px;
    animation: brandScroller 5s linear infinite;
}
.s-brand-block span {
    font-size: 20px;
    font-family: var(--main-hard-font);
    font-weight: 800;
    color: var(--black-main-clr);
}

@keyframes brandScroller {
    0% {
        transform: translateX(0%);
    }
    100% {
        transform: translateX(var(--perc));
    }
}

.s-brand-block {
    display: flex;
    align-items: center;
    gap: 5px;
    justify-content: center;
    min-width: fit-content;
    margin-right: 50px;
    padding-right: 10px;
}

.s-brand-block img {
    height: 50px;
}
<section class="services-brand">
        <div class="s-brand-wrapper scroller__inner">
            <div class="s-brand-block">
                <img src="https://picsum.photos/id/9/5000/3269.jpg" alt="web development">
                <span>Web Development</span>
            </div>
            <div class="s-brand-block">
                <img src="https://picsum.photos/id/7/4728/3168.jpg" alt="Digital Marketing">
                <span>Digital Marketing</span>
            </div>
            <div class="s-brand-block">
                <img src="https://picsum.photos/id/4/5000/3333.jpg" alt="Content Creation">
                <span>Content Creation</span>
            </div>
            <div class="s-brand-block">
                <img src="https://picsum.photos/id/20/3670/2462.jpg" alt="Design/Brending">
                <span>Design/Brending</span>
            </div>
            <div class="s-brand-block">
                <img src="https://picsum.photos/id/1/5000/3333.jpg" alt="Seo">
                <span>SEO</span>
            </div>
            <div class="s-brand-block">
                <img src="https://picsum.photos/id/48/5000/3333.jpg" alt="UX/UI">
                <span>UX/UI</span>
            </div>
        </div>
    </section>

© www.soinside.com 2019 - 2024. All rights reserved.