У меня есть анимация бегущей текстовой области. При наведении курсора анимация приостанавливается и отображается градиент как «цвет текста». Мышь отслеживается, чтобы привязать центр черного градиента к движению мыши.
Цель:
Градиент на тексте должен распространяться по всему тексту. ширина. Изображения внутри текста не должны быть затронуты. Центр градиента всегда должен быть черного цвета. В идеале градиент должен быть на уровне .marquee (обертки), чтобы на него не влияла анимация. (.marqueeConetent анимируется)
Задача:
Создаются разные контексты наложения, поэтому сложно разместить изображения над наложением градиента. Из-за текстовой анимации контент в какой-то момент дублируется и заменяется -> приводит к аномалиям, когда градиент не затрагивает каждый текстовый блок.
Что я пробовал:
подход наложения смешанного режима – сложно преодолеть различные контексты наложения, поэтому изображения всегда подвергаются воздействию.
подход с использованием текста фонового клипа – либо изменяется центр градиента или эффект применяется к каждому текстовому блоку индивидуально.
Есть ли какой-нибудь способ добиться того, что я ищу? Есть ли способ предотвратить воздействие на изображения в контексте нижнего стека наложения с режимом смешивания в контексте с более высоким стеком?
Код: Выделить всё
const marquees = document.querySelectorAll(".marquee");
// If recuded motion isn't activated we add the animation
if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
addMarqueeAnimation();
}
function addMarqueeAnimation() {
marquees.forEach((marquee) => {
// add data-animated="true" to every `.marquee` on the page
marquee.setAttribute("data-animated", true);
// Make an array from the elements within .marquee
const scrollerContent = Array.from(marquee.children);
// For each item in the array, clone it
// add aria-hidden to it
// add it into the .marquee
scrollerContent.forEach((item) => {
const duplicatedItem = item.cloneNode(true);
duplicatedItem.setAttribute("aria-hidden", true);
marquee.appendChild(duplicatedItem);
});
});
}
//track mouse for gradient hover
const button = document.querySelectorAll(".marquee");
for (let i = 0; i < button.length; i++) {
button[i].addEventListener("mousemove", (e) => {
const { x, y } = button[i].getBoundingClientRect();
button[i].style.setProperty("--x", e.clientX - x + "px");
button[i].style.setProperty("--y", e.clientY - y + "px");
});
}
Код: Выделить всё
body {
margin: 0;
font-family: system-ui;
font-size: 2.5rem;
background: white;
color: black;
}
section {
position: relative;
}
.imgEmoji {
height: 2.5rem;
width: 2.5rem;
margin-bottom: -6px;
position: relative;
z-index: 999;
mix-blend-mode: unset;
}
.marquee {
--gap: 1.5rem;
display: flex;
gap: var(--gap);
overflow-x: clip;
background: white;
}
.marqueeContent {
display: flex;
gap: calc(var(--gap));
flex-shrink: 0;
align-items: center;
justify-content: space-around;
min-width: 100%;
padding-block: 0.75rem;
background: inherit;
}
/* Animation */
.marquee[data-animated="true"] .marqueeContent {
animation: scroll var(--marquee-duration, 15.5s)
var(--marquee-direction, forwards) linear infinite;
}
.marquee[data-animated="true"]:hover .marqueeContent {
animation-play-state: paused;
}
@keyframes scroll {
to {
transform: translate(
calc(-50% - calc(var(--gap) / 2))
);
}
}
/* Direction */
.marquee[data-direction="left"] {
--marquee-direction: forwards;
}
/* Speed */
.marquee[data-speed="faster"] {
--marquee-duration: 5s;
}
/* IDEA 1 */
/* pseudo element on non animated wrapper
+ it stays the same and is not animated
- images get effected since different stacking context
*/
.marquee:hover::after {
content: "";
height: 100%;
width: 100%;
top: 0;
left: 0;
background: radial-gradient(
circle at var(--x, 0) var(--y, 0),
black 0vw,
red 21vw,
green 34vw,
yellow 51vw
);
mix-blend-mode: screen;
position: absolute;
z-index: 2;
}
/* IDEA 2 */
/* pseudo element on animated content
+ images are not effected
- since the pseudo element is also animated the gradient center changes
- when parts of both content groups are shown the gradient isn't the same on all elements
.marqueeContent:hover::after {
content: "";
height: 100%;
width: 100%;
top: 0;
left: 0;
background: radial-gradient(
circle at var(--x, 0) var(--y, 0),
black 0vw,
red 21vw,
green 34vw,
yellow 51vw
);
mix-blend-mode: screen;
position: absolute;
z-index: 2;
}
*/
/* IDEA 3 */
/* background clip on all spans and a with text
+ images are not effected
- gradient is different and limited to each text element
span:not(:has(img)), .marqueeContent a {
background: radial-gradient(
circle at var(--x, 0) var(--y, 0),
black 0vw,
red 21vw,
green 34vw,
yellow 51vw
);
background-clip: text;
color: transparent;
}
*/
/* IDEA 4 */
/* background clip on wraper
+ images are not effected
- gradient is wierd the center is moving
.marquee:hover {
background: radial-gradient(
circle at var(--x, 0) var(--y, 0),
black 0vw,
red 21vw,
green 34vw,
yellow 51vw
);
background-clip: text;
color: transparent;
}
*/
Код: Выделить всё
Happy Holidays
[img]https://shorturl.at/kzntl[/img]
[img]https://shorturl.at/kzntl[/img]
Happy Holidays
[img]https://shorturl.at/kzntl[/img]
[img]https://shorturl.at/kzntl[/img]
Happy Holidays
[img]https://shorturl.at/kzntl[/img]
[img]https://shorturl.at/kzntl[/img]
Happy Holidays
[img]https://shorturl.at/kzntl[/img]
[img]https://shorturl.at/kzntl[/img]
Подробнее здесь: https://stackoverflow.com/questions/793 ... e-effected