<!--
`marquee` class turns elements into <marquee>-like elements
`data-text` attribute is used to define <marquee> text content
-->
<figure class="marquee marquee--navy" data-text="Like a <marquee> element">
<!-- A visually-hidden `<span>` allows screen reader to still read content -->
<span class="sr-only">Like a <marquee> element</span>
</figure>
<!-- `marquee--reverse` class reverses the scroll animation -->
<figure class="marquee marquee--reverse marquee--beet" data-text="Powered by some CSS">
<span class="sr-only">Powered by some CSS</span>
</figure>
<figure class="marquee marquee--flamingo" data-text="Like a <marquee> element">
<span class="sr-only">Like a <marquee> element</span>
</figure>
<figure class="marquee marquee--reverse marquee--ochre" data-text="Powered by some CSS">
<span class="sr-only">Powered by some CSS</span>
</figure>
<figure class="marquee marquee--butter" data-text="Like a <marquee> element">
<span class="sr-only">Like a <marquee> element</span>
</figure>
<figure class="marquee marquee--reverse marquee--mantis" data-text="Powered by some CSS">
<span class="sr-only">Powered by some CSS</span>
</figure>
/**
* Core, likely what you want to copy/paste with little change
*/
.marquee {
overflow: hidden;
display: block;
}
.marquee::before {
display: block;
white-space: pre;
/* Abusing `content` property and `attr` function to duplicate content in CSS */
content: attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text) " " attr(data-text);
width: fit-content;
transform: translate3d(-2%, 0, 0);
will-change: transform;
}
/**
* Only run animations when reduced motion is not set
* Thanks @patrick_h_lauke@mastodon.social for the heads up!
*/
@media (prefers-reduced-motion: no-preference) {
.marquee::before {
animation: marquee 6s linear infinite;
}
.marquee--reverse::before {
animation-direction: reverse;
}
}
@keyframes marquee {
0% {
/**
* -2% is used to start scrolling with an offset (visual only)
*/
transform: translate3d(-2%, 0, 0);
}
100% {
/**
* -2% offset has to be preserved
*
* Content is duplicated 20 times
* 100% / 20 = 5 % = "1 content length"
*
* -1px seems to prevent a small jump between each loop
*/
transform: translate3d(calc(-2% - 5% - 1px), 0, 0);
}
}
/**
* From here, style marquee however you'd like
*/
.marquee {
margin: 0;
display: flex;
align-items: center;
font-size: clamp(1rem, 4vh, 3rem);
flex: 1;
}
.marquee--navy {
background: #54669c;
}
.marquee--beet {
background: #a54a5e;
}
.marquee--flamingo {
background: #e84311;
}
.marquee--ochre {
background: #f27502;
}
.marquee--butter {
background: #ffb005;
}
.marquee--mantis {
background: #759f53;
}
body {
margin: 0;
font-family: sans-serif;
background: #fffefe;
color: #1f1919;
height: 100vh;
display: flex;
flex-direction: column;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.