Words glide in from the right and leave to the left, like slides in a carousel, fading out at the edges of their slot. A mask-image gradient makes the soft edges, so it works on any background.
Also known as: text carousel css, sliding words animation, horizontal word rotator.
<div class="txt-horizontal-text-carousel">Trusted by
<span class="txt-horizontal-text-carousel-words">
<span style="--i: 0">startups</span>
<span style="--i: 1">agencies</span>
<span style="--i: 2">schools</span>
</span>
</div>.txt-horizontal-text-carousel {
--c: var(--txt-color, #3b82f6);
font-size: var(--txt-size, 32px);
font-family: system-ui, sans-serif;
font-weight: 700;
line-height: 1.2;
display: flex;
align-items: baseline;
white-space: nowrap;}
.txt-horizontal-text-carousel-words {
display: inline-grid;
padding: 0 0.35em;
overflow: hidden;
color: var(--c);
-webkit-mask-image: linear-gradient(90deg, transparent, #000 0.35em, #000 calc(100% - 0.35em), transparent);
mask-image: linear-gradient(90deg, transparent, #000 0.35em, #000 calc(100% - 0.35em), transparent);
}
.txt-horizontal-text-carousel-words span {
grid-area: 1 / 1;
/* 3 words x 2.2s = 6.6s */
animation: txt-horizontal-text-carousel-slide 6.6s cubic-bezier(0.7, 0, 0.25, 1) infinite;
animation-delay: calc(var(--i) * 2.2s - 6.6s);
}
.txt-horizontal-text-carousel-words span:not(:first-child) {
transform: translateX(calc(100% + 0.4em));
}
@keyframes txt-horizontal-text-carousel-slide {
0%, 24.24% { transform: translateX(0); opacity: 1; }
/* fully out of the slot and faded before it jumps back to the right */
33.33% { transform: translateX(calc(-100% - 0.4em)); opacity: 0; }
33.34% { transform: translateX(calc(100% + 0.4em)); opacity: 0; }
90.91% { transform: translateX(calc(100% + 0.4em)); opacity: 1; }
100% { transform: translateX(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
.txt-horizontal-text-carousel, .txt-horizontal-text-carousel *, .txt-horizontal-text-carousel::before, .txt-horizontal-text-carousel::after, .txt-horizontal-text-carousel *::before, .txt-horizontal-text-carousel *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--txt-color on the element or a parent.
Currently previewing #3b82f6.--txt-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 40px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.