I need to make an endless running line with gradient text that changes as it moves, as in the example, it works, but there are problems in Safari, everything twitches there and the letters seem to run into each other, maybe something can be done so that it also works in Safari without freezes. Maybe there are other solutions for such an implementation.
Example marquee
document.querySelectorAll('.running-lines__wrapper').forEach(
(line) => {
const content = line.innerHTML;
const duplicateCount = line.getAttribute('data-duplicate-count') || 1;
const duration =
parseInt(line.getAttribute('data-duration'), 10) || 10000;
const direction = line.getAttribute('data-direction') || 'normal';
let duplicatedContent = '';
for (let i = 0; i < duplicateCount; i++) {
duplicatedContent += content;
}
line.innerHTML = duplicatedContent;
const lineText = line.querySelectorAll('.running-lines__items');
lineText.forEach((text) => {
const fromFrame = {
textIndent: 0
};
const toFrame = {
textIndent: '-100%'
};
const options = {
duration,
iterations: Infinity,
direction
};
text.animate([fromFrame, toFrame], options);
});
});
.running-lines {
font-family: "Poppins";
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
row-gap: 0.5rem;
overflow: hidden;
background-image: linear-gradient(92.55deg,
#852fff 0%,
#dd26ed 48.5%,
#ed2662 100%);
-webkit-background-clip: text;
background-clip: text;
padding-top: 4rem;
padding-bottom: 4rem;
mix-blend-mode: lighten;
}
@media (min-width: 956px) {
.running-lines {
row-gap: 1rem;
padding-top: 3.5rem;
padding-bottom: 3.5rem;
}
}
@media (min-width: 1184px) {
.running-lines {
row-gap: 1.25rem;
}
}
.running-lines__wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding-top: 0.625rem;
padding-bottom: 0.625rem;
}
.running-lines__items {
margin-bottom: 0;
text-wrap: nowrap;
will-change: text-indent;
/* animation: marquee 15s linear infinite; */
}
.running-lines__item {
margin-right: 2rem;
font-size: 1.25rem;
line-height: 1.5rem;
font-style: italic;
color: transparent;
}
@media (min-width: 956px) {
.running-lines__item {
margin-right: 3rem;
font-size: 1.5rem;
line-height: 2rem;
}
}
@media (min-width: 1184px) {
.running-lines__item {
margin-right: 4rem;
}
}
@keyframes marquee {
from {
text-indent: 0;
}
to {
text-indent: -100%;
}
}
<div class="running-lines">
<div class="running-lines__wrapper" data-duration="28000" data-duplicate-count="7">
<p class="running-lines__items">
<span class="running-lines__item">Security Kit</span>
<span class="running-lines__item">Honeypot</span>
<span class="running-lines__item">Antibot</span>
<span class="running-lines__item">Flood Control</span>
<span class="running-lines__item">Move 403 to 404</span>
<span class="running-lines__item">Rabbit Hole</span>
<span class="running-lines__item">Username Enumeration Prevention</span>
</p>
</div>
<div class="running-lines__wrapper" data-duration="50000" data-direction="reverse" data-duplicate-count="7">
<p class="running-lines__items">
<span class="running-lines__item">Content Moderation</span>
<span class="running-lines__item">Workflows</span>
<span class="running-lines__item">Simple Menu Permissions</span>
<span class="running-lines__item">Group Node</span>
<span class="running-lines__item">Scheduler</span>
<span class="running-lines__item">Media</span>
</p>
</div>
<div class="running-lines__wrapper" data-duration="40000" data-duplicate-count="7">
<p class="running-lines__items">
<span class="running-lines__item">Paragraphs & Paragraphs Browser</span>
<span class="running-lines__item">Group</span>
<span class="running-lines__item">Gin & Gin Toolbar</span>
<span class="running-lines__item">Crop & Image Widget Crop</span>
<span class="running-lines__item">Migrate & Migrate Plus</span>
</p>
</div>
</div>
I need to make an endless running line with gradient text that changes as it moves, as in the example, it works, but there are problems in Safari, everything twitches there and the letters seem to run into each other, maybe something can be done so that it also works in Safari without freezes. Maybe there are other solutions for such an implementation.
Example marquee
document.querySelectorAll('.running-lines__wrapper').forEach(
(line) => {
const content = line.innerHTML;
const duplicateCount = line.getAttribute('data-duplicate-count') || 1;
const duration =
parseInt(line.getAttribute('data-duration'), 10) || 10000;
const direction = line.getAttribute('data-direction') || 'normal';
let duplicatedContent = '';
for (let i = 0; i < duplicateCount; i++) {
duplicatedContent += content;
}
line.innerHTML = duplicatedContent;
const lineText = line.querySelectorAll('.running-lines__items');
lineText.forEach((text) => {
const fromFrame = {
textIndent: 0
};
const toFrame = {
textIndent: '-100%'
};
const options = {
duration,
iterations: Infinity,
direction
};
text.animate([fromFrame, toFrame], options);
});
});
.running-lines {
font-family: "Poppins";
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
row-gap: 0.5rem;
overflow: hidden;
background-image: linear-gradient(92.55deg,
#852fff 0%,
#dd26ed 48.5%,
#ed2662 100%);
-webkit-background-clip: text;
background-clip: text;
padding-top: 4rem;
padding-bottom: 4rem;
mix-blend-mode: lighten;
}
@media (min-width: 956px) {
.running-lines {
row-gap: 1rem;
padding-top: 3.5rem;
padding-bottom: 3.5rem;
}
}
@media (min-width: 1184px) {
.running-lines {
row-gap: 1.25rem;
}
}
.running-lines__wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding-top: 0.625rem;
padding-bottom: 0.625rem;
}
.running-lines__items {
margin-bottom: 0;
text-wrap: nowrap;
will-change: text-indent;
/* animation: marquee 15s linear infinite; */
}
.running-lines__item {
margin-right: 2rem;
font-size: 1.25rem;
line-height: 1.5rem;
font-style: italic;
color: transparent;
}
@media (min-width: 956px) {
.running-lines__item {
margin-right: 3rem;
font-size: 1.5rem;
line-height: 2rem;
}
}
@media (min-width: 1184px) {
.running-lines__item {
margin-right: 4rem;
}
}
@keyframes marquee {
from {
text-indent: 0;
}
to {
text-indent: -100%;
}
}
<div class="running-lines">
<div class="running-lines__wrapper" data-duration="28000" data-duplicate-count="7">
<p class="running-lines__items">
<span class="running-lines__item">Security Kit</span>
<span class="running-lines__item">Honeypot</span>
<span class="running-lines__item">Antibot</span>
<span class="running-lines__item">Flood Control</span>
<span class="running-lines__item">Move 403 to 404</span>
<span class="running-lines__item">Rabbit Hole</span>
<span class="running-lines__item">Username Enumeration Prevention</span>
</p>
</div>
<div class="running-lines__wrapper" data-duration="50000" data-direction="reverse" data-duplicate-count="7">
<p class="running-lines__items">
<span class="running-lines__item">Content Moderation</span>
<span class="running-lines__item">Workflows</span>
<span class="running-lines__item">Simple Menu Permissions</span>
<span class="running-lines__item">Group Node</span>
<span class="running-lines__item">Scheduler</span>
<span class="running-lines__item">Media</span>
</p>
</div>
<div class="running-lines__wrapper" data-duration="40000" data-duplicate-count="7">
<p class="running-lines__items">
<span class="running-lines__item">Paragraphs & Paragraphs Browser</span>
<span class="running-lines__item">Group</span>
<span class="running-lines__item">Gin & Gin Toolbar</span>
<span class="running-lines__item">Crop & Image Widget Crop</span>
<span class="running-lines__item">Migrate & Migrate Plus</span>
</p>
</div>
</div>
Share
Improve this question
asked Mar 15 at 10:02
Clop1986Clop1986
311 silver badge3 bronze badges
3
|
1 Answer
Reset to default 2I have reworked my solution to the question, now there are no jerks on all devices, I am posting it here, maybe it will be useful to someone
document.querySelectorAll('.running-lines__wrapper').forEach((line) => {
const $items = line.querySelector('.running-lines__items');
const content = $items.innerHTML;
const duplicateCount = line.getAttribute('data-duplicate-count') || 1;;
let duration = parseFloat(line.getAttribute('data-duration')) || 1;
const direction = line.getAttribute('data-direction') || 'normal';
let scrollAmount = 0;
let bgPosition = 0;
if (direction === 'reverse') {
line.style.direction = 'rtl';
duration = -duration;
}
$items.innerHTML = content.repeat(duplicateCount);
const startScrolling = () => {
const scrollStep = () => {
scrollAmount += duration;
bgPosition += duration;
line.scrollLeft = scrollAmount;
$items.style.backgroundPositionX =
direction === 'reverse'
? `calc(100% - ${Math.abs(bgPosition)}px)`
: `${bgPosition}px`;
const itemsRect = $items.getBoundingClientRect();
const isReverse = direction === 'reverse';
const threshold = itemsRect.width / duplicateCount;
if (
(isReverse && scrollAmount <= -threshold) ||
(!isReverse && scrollAmount >= threshold)
) {
const adjustment = isReverse ? threshold : -threshold;
scrollAmount += adjustment;
bgPosition += adjustment;
}
requestAnimationFrame(scrollStep);
};
scrollStep();
};
startScrolling();
});
body {
margin: 0;
padding: 0;
font-family: "Poppins";
}
.running-lines {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
row-gap: 0.5rem;
padding-top: 4rem;
padding-bottom: 4rem;
}
@media (min-width: 956px) {
.running-lines {
row-gap: 1rem;
padding-top: 3.5rem;
padding-bottom: 3.5rem;
}
}
@media (min-width: 1184px) {
.running-lines {
row-gap: 1.25rem;
}
}
.running-lines__wrapper {
overflow: hidden;
padding-top: 0.625rem;
padding-bottom: 0.625rem;
}
.running-lines__items {
display: inline-block;
white-space: nowrap;
background-image: linear-gradient(
92.55deg,
#852fff 0%,
#dd26ed 48.5%,
#ed2662 100%
);
background-size: 100vw;
-webkit-background-clip: text;
background-clip: text;
background-position: left;
background-repeat: no-repeat;
}
.running-lines__item {
margin-right: 2rem;
font-size: 1.25rem;
line-height: 1.5rem;
font-style: italic;
color: transparent;
}
@media (min-width: 956px) {
.running-lines__item {
margin-right: 3rem;
font-size: 1.5rem;
line-height: 2rem;
}
}
@media (min-width: 1184px) {
.running-lines__item {
margin-right: 4rem;
}
}
<div class="running-lines">
<div class="running-lines__wrapper" data-duration="0.4" data-duplicate-count="7">
<div class="running-lines__items">
<span class="running-lines__item">Security Kit</span>
<span class="running-lines__item">Honeypot</span>
<span class="running-lines__item">Antibot</span>
<span class="running-lines__item">Flood Control</span>
<span class="running-lines__item">Move 403 to 404</span>
<span class="running-lines__item">Rabbit Hole</span>
<span class="running-lines__item">Username Enumeration Prevention</span>
</div>
</div><div class="running-lines__wrapper" data-duration="0.8" data-direction="reverse" data-duplicate-count="7">
<div class="running-lines__items">
<span class="running-lines__item">Content Moderation</span>
<span class="running-lines__item">Workflows</span>
<span class="running-lines__item">Simple Menu Permissions</span>
<span class="running-lines__item">Group Node</span>
<span class="running-lines__item">Scheduler</span>
<span class="running-lines__item">Media</span>
</div>
</div><div class="running-lines__wrapper" data-duration="0.6" data-duplicate-count="7">
<div class="running-lines__items">
<span class="running-lines__item">Paragraphs & Paragraphs Browser</span>
<span class="running-lines__item">Group</span>
<span class="running-lines__item">Gin & Gin Toolbar</span>
<span class="running-lines__item">Crop & Image Widget Crop</span>
<span class="running-lines__item">Migrate & Migrate Plus</span>
</div>
</div>
</div>
text-indent
is animated – imhvost Commented Mar 15 at 21:55