remarqueeble
Version:
Custom element tribute to the cursed glory of marquee.
156 lines (132 loc) • 3.51 kB
CSS
/*! remarqueeble v0.7.0 | (c) 2026 Rémino Rem <https://remino.net/> | ISC Licence */
.re-marquee {
--re-marquee-duration: 20s;
--re-marquee-iteration-count: infinite;
--re-marquee-play-state: running;
--re-marquee-timing-function: linear;
container-type: inline-size;
display: block;
overflow: hidden;
white-space: nowrap;
}
.re-marquee__track {
animation: re-marquee-scroll var(--re-marquee-duration)
var(--re-marquee-timing-function);
animation-fill-mode: both;
animation-iteration-count: var(--re-marquee-iteration-count);
animation-play-state: var(--re-marquee-play-state);
display: inline-block;
min-inline-size: max-content;
padding-inline-start: 100%;
will-change: transform;
}
.re-marquee--reverse > .re-marquee__track,
.re-marquee--right > .re-marquee__track,
.re-marquee--down > .re-marquee__track {
animation-direction: reverse;
}
.re-marquee--alternate > .re-marquee__track {
animation-direction: alternate;
animation-name: re-marquee-scroll-alternate-x;
padding-inline-start: 0;
}
.re-marquee--paused {
--re-marquee-play-state: paused;
}
.re-marquee--pause-on-hover:hover {
--re-marquee-play-state: paused;
}
.re-marquee--vertical,
.re-marquee--up,
.re-marquee--down {
block-size: 12rem;
container-type: size;
position: relative;
white-space: normal;
}
.re-marquee--vertical > .re-marquee__track,
.re-marquee--up > .re-marquee__track,
.re-marquee--down > .re-marquee__track {
animation-name: re-marquee-scroll-y;
display: inline-flex;
flex-direction: column;
inset-block-start: 100%;
inset-inline-start: 0;
min-inline-size: auto;
padding-inline-start: 0;
position: absolute;
}
.re-marquee--alternate.re-marquee--vertical > .re-marquee__track,
.re-marquee--alternate.re-marquee--up > .re-marquee__track,
.re-marquee--alternate.re-marquee--down > .re-marquee__track {
animation-name: re-marquee-scroll-alternate-y;
}
.re-marquee--alternate.re-marquee--right > .re-marquee__track,
.re-marquee--alternate.re-marquee--down > .re-marquee__track {
animation-direction: alternate-reverse;
}
@media (prefers-reduced-motion: reduce) {
.re-marquee {
overflow: auto;
}
.re-marquee__track {
animation: none;
padding-inline-start: 0;
position: static;
transform: none;
will-change: auto;
}
}
@keyframes re-marquee-scroll {
from {
transform: translateX(var(--re-marquee-start-pos, 0));
}
to {
transform: translateX(var(--re-marquee-end-pos, -100%));
}
}
@keyframes re-marquee-scroll-alternate-x {
from {
transform: translateX(var(--re-marquee-start-pos, calc(100cqw - 100%)));
}
to {
transform: translateX(var(--re-marquee-end-pos, 0));
}
}
@keyframes re-marquee-scroll-y {
from {
inset-block-start: 100%;
transform: translateY(var(--re-marquee-start-pos, 0));
}
to {
inset-block-start: 0;
transform: translateY(var(--re-marquee-end-pos, -100%));
}
}
@keyframes re-marquee-scroll-alternate-y {
from {
inset-block-start: 0;
transform: translateY(var(--re-marquee-start-pos, calc(100cqh - 100%)));
}
to {
inset-block-start: 0;
transform: translateY(var(--re-marquee-end-pos, 0));
}
}
@supports (height: 1cqh) {
.re-marquee--vertical > .re-marquee__track,
.re-marquee--up > .re-marquee__track,
.re-marquee--down > .re-marquee__track {
inset-block-start: 0;
}
@keyframes re-marquee-scroll-y {
from {
inset-block-start: 0;
transform: translateY(var(--re-marquee-start-pos, 100cqh));
}
to {
inset-block-start: 0;
transform: translateY(var(--re-marquee-end-pos, -100%));
}
}
}