Absolutely! The main issue causing the "jump" in your marquee is the calculation in your keyframes and the structure of your HTML/CSS.
Why does this happen?
You are animating a single .marquee element to the left (translateX), duplicating your logos, hoping the animation will seamlessly loop as the duplicated portion comes into view. But the calculation in:
transform: translateX(calc(-50% - 3rem));
is rarely a perfect fit—especially as the gap between items is not accounted for across all items evenly. This small offset can cause the "jump".
Best Practice: You should:
- Duplicate the
lis in code (what you did is okay if you match everything exactly). - Animate
.marqueeleft by exactly half its width (-50%), so the start and the end match up perfectly without a jump. - Set the
.marqueewidth to double the content so both halves are identical. - Important: For a pure CSS solution, the content must be perfectly symmetrical, including gaps.
The Fix
Change only a few key things:
1. Update the Markup to duplicate contents via code, not manually (optional, but less error-prone).
You can use:
<ul class="marquee">
<!-- logos here -->
</ul>
and use CSS to duplicate via ::after if number of items is fixed, or keep your current markup.
2. Update the CSS:
a. Width Add this:
.marquee {
width: max-content;
min-width: 100%;
}
b. Animation
You want to slide exactly -50% of its width:
@keyframes marquee {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
.marquee {
animation: marquee 10s linear infinite;
display: flex;
gap: 6rem;
width: max-content;
min-width: 100%;
}
(Change animation speed as needed; 10s is just an example.)
c. Container overflow
The CSS property overflow: clip; is not well supported everywhere; use overflow: hidden;:
.marquee-container {
overflow: hidden;
}
3. Remove the "half gap" fudge (- 3rem) in your keyframes.
This fudge is rarely right and causes the jump! Let flex/gap handle spacing.
Working Example (updated):
HTML
<div class="marquee-container">
<ul class="marquee">
<li><img src="https://picsum.photos/200/64" alt="Image"></li>
<li><img src="https://picsum.photos/200/64" alt="Image"></li>
<li><img src="https://picsum.photos/200/64" alt="Image"></li>
<li><img src="https://picsum.photos/200/64" alt="Image"></li>
<li><img src="https://picsum.photos/200/64" alt="Image"></li>
<!-- Duplicate for seamless effect -->
<li aria-hidden="true"><img src="https://picsum.photos/200/64" alt="Image"></li>
<li aria-hidden="true"><img src="https://picsum.photos/200/64" alt="Image"></li>
<li aria-hidden="true"><img src="https://picsum.photos/200/64" alt="Image"></li>
<li aria-hidden="true"><img src="https://picsum.photos/200/64" alt="Image"></li>
<li aria-hidden="true"><img src="https://picsum.photos/200/64" alt="Image"></li>
</ul>
</div>
CSS
li {
list-style: none;
}
.marquee-container {
max-width: 1000px;
margin: 4rem auto 0;
overflow: hidden;
background: red;
mask-image: linear-gradient(
to right,
transparent 0%,
black 10%,
black 90%,
transparent 100%
);
}
.marquee {
display: flex;
gap: 6rem;
background: yellow;
width: max-content;
min-width: 100%;
animation: marquee 10s linear infinite;
}
.marquee > li {
flex-shrink: 0;
}
.marquee > li > img {
height: 60px;
}
@keyframes marquee {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
.marquee:hover {
animation-play-state: paused;
}
.marquee img {
filter: grayscale(100%);
transition: filter 0.2s;
}
.marquee img:hover {
filter: grayscale(0%);
}
Summary:
- Duplicate your logos for a seamless effect.
- Animate to
-50%(no fudge factors). - Set container to
overflow: hidden;. - Ensure gaps are consistent.
That should remove the jump and provide a seamless, continuous marquee! If it still "jumps," double-check that your duplicated logos (including gaps) are exactly the same as the first set.
Let me know if you want a JavaScript-powered version for more flexibility!