Logo list carousel
Demo
What they say about us
How to
Prepare a long image in which the logo is tied together. The image I used here is 30px in height and 960px in width.
Arrange two images consecutively and wrap them in div tags. The images should not be responsive so it's mandatory to specify the height and width properly. The div tag that wraps the images should be the 2 times of the image's width(1920px) because the image should be aligned horizontally.
html
<div class="h-[30px] w-[1920px]">
<img :src="src" class="h-[30px] w-[960px]" />
<img :src="src" class="h-[30px] w-[960px]" />
</div>
Wrap it one more with a overflow-x-hidden
div so that the container does not leave the viewport.
html
<div class="overflow-x-hidden">
<div class="h-[30px] w-[1920px]">
<img :src="src" class="h-[30px] w-[960px]" />
<img :src="src" class="h-[30px] w-[960px]" />
</div>
</div>
Next, define an infinite loop css animation scoll
that moves the x-axis as much as the image size.
css
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-960px);
}
}
.animate {
animation: scroll 20s linear infinite;
}
That's it! Isn't it really that simple, right?
Furthermore, we can delay the image loading and scroll animation as shown in the code below.
Source code
vue
<template>
<div class="min-h-[100px] bg-blue-900 p-10" ref="root" :class="$style.root">
<p class="mb-8 text-center typo-title">What they say about us</p>
<div class="relative overflow-x-hidden">
<div :class="[$style.logoContainer, { [$style.animate]: doAnimate }]">
<template v-if="src">
<img v-for="(_, idx) in new Array(nbItems)" :key="idx" :src="src" :class="$style.logoImage" />
</template>
</div>
</div>
</div>
</template>
<script setup>
import { useElementVisibility } from '@vueuse/core';
import logoImage from './logos.png';
const root = ref(null);
const src = ref(null);
const doAnimate = ref(false);
const nbItems = 2;
const isVisible = useElementVisibility(root);
watch(isVisible, (visible) => {
if (visible && !src.value) {
// image lazy load
src.value = logoImage;
}
// animate only when it's visible to save computing resource
doAnimate.value = visible;
});
</script>
<style module>
.root {
--nb-items: v-bind(nbItems);
--item-width: 960px;
--item-height: 30px;
}
.logoContainer {
width: calc(var(--item-width) * var(--nb-items));
min-height: var(--item-height);
}
.logoImage {
width: var(--item-width);
height: var(--item-height);
}
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-960px);
}
}
.animate {
animation: scroll 20s linear infinite;
}
</style>