Image-Heavy Brand Wall — Multi-Row Masonry Marquee Background
A full-bleed, three-row wall of mixed-width imagery drifting at three different speeds and directions — the 'living moodboard' agencies and creator brands run behind hero copy. Rows use varied tile widths and subtle tilts so it reads masonry, a dark scrim keeps foreground text at AAA contrast, and the whole wall is aria-hidden because it is decoration by design.
Published
The code
<section class="mqs-09" aria-label="Image brand wall marquee demo">
<div class="mqs-09__wall" aria-hidden="true">
<div class="mqs-09__viewport">
<div class="mqs-09__group" style="--speed:48s">
<span class="mqs-09__tile" style="width:220px;--g:linear-gradient(135deg,#f472b6,#c026d3)"></span>
<span class="mqs-09__tile" style="width:150px;--g:linear-gradient(135deg,#38bdf8,#1d4ed8)"></span>
<span class="mqs-09__tile" style="width:260px;--g:linear-gradient(135deg,#fbbf24,#ea580c)"></span>
<span class="mqs-09__tile" style="width:170px;--g:linear-gradient(135deg,#34d399,#0f766e)"></span>
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#a78bfa,#6d28d9)"></span>
</div>
<div class="mqs-09__group" style="--speed:48s">
<span class="mqs-09__tile" style="width:220px;--g:linear-gradient(135deg,#f472b6,#c026d3)"></span>
<span class="mqs-09__tile" style="width:150px;--g:linear-gradient(135deg,#38bdf8,#1d4ed8)"></span>
<span class="mqs-09__tile" style="width:260px;--g:linear-gradient(135deg,#fbbf24,#ea580c)"></span>
<span class="mqs-09__tile" style="width:170px;--g:linear-gradient(135deg,#34d399,#0f766e)"></span>
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#a78bfa,#6d28d9)"></span>
</div>
</div>
<div class="mqs-09__viewport">
<div class="mqs-09__group mqs-09__group--rev" style="--speed:62s">
<span class="mqs-09__tile" style="width:180px;--g:linear-gradient(135deg,#fb7185,#be123c)"></span>
<span class="mqs-09__tile" style="width:240px;--g:linear-gradient(135deg,#4ade80,#15803d)"></span>
<span class="mqs-09__tile" style="width:140px;--g:linear-gradient(135deg,#facc15,#a16207)"></span>
<span class="mqs-09__tile" style="width:210px;--g:linear-gradient(135deg,#22d3ee,#0e7490)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#c084fc,#7e22ce)"></span>
</div>
<div class="mqs-09__group mqs-09__group--rev" style="--speed:62s">
<span class="mqs-09__tile" style="width:180px;--g:linear-gradient(135deg,#fb7185,#be123c)"></span>
<span class="mqs-09__tile" style="width:240px;--g:linear-gradient(135deg,#4ade80,#15803d)"></span>
<span class="mqs-09__tile" style="width:140px;--g:linear-gradient(135deg,#facc15,#a16207)"></span>
<span class="mqs-09__tile" style="width:210px;--g:linear-gradient(135deg,#22d3ee,#0e7490)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#c084fc,#7e22ce)"></span>
</div>
</div>
<div class="mqs-09__viewport">
<div class="mqs-09__group" style="--speed:55s">
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#818cf8,#3730a3)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#f97316,#9a3412)"></span>
<span class="mqs-09__tile" style="width:250px;--g:linear-gradient(135deg,#2dd4bf,#115e59)"></span>
<span class="mqs-09__tile" style="width:145px;--g:linear-gradient(135deg,#e879f9,#a21caf)"></span>
<span class="mqs-09__tile" style="width:190px;--g:linear-gradient(135deg,#94a3b8,#334155)"></span>
</div>
<div class="mqs-09__group" style="--speed:55s">
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#818cf8,#3730a3)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#f97316,#9a3412)"></span>
<span class="mqs-09__tile" style="width:250px;--g:linear-gradient(135deg,#2dd4bf,#115e59)"></span>
<span class="mqs-09__tile" style="width:145px;--g:linear-gradient(135deg,#e879f9,#a21caf)"></span>
<span class="mqs-09__tile" style="width:190px;--g:linear-gradient(135deg,#94a3b8,#334155)"></span>
</div>
</div>
</div>
<div class="mqs-09__fore">
<h3 class="mqs-09__hero">Made with the brands you love</h3>
<p class="mqs-09__sub">Swap the gradient tiles for campaign imagery — the wall is pure decoration, invisible to screen readers.</p>
</div>
</section><section class="mqs-09" aria-label="Image brand wall marquee demo">
<div class="mqs-09__wall" aria-hidden="true">
<div class="mqs-09__viewport">
<div class="mqs-09__group" style="--speed:48s">
<span class="mqs-09__tile" style="width:220px;--g:linear-gradient(135deg,#f472b6,#c026d3)"></span>
<span class="mqs-09__tile" style="width:150px;--g:linear-gradient(135deg,#38bdf8,#1d4ed8)"></span>
<span class="mqs-09__tile" style="width:260px;--g:linear-gradient(135deg,#fbbf24,#ea580c)"></span>
<span class="mqs-09__tile" style="width:170px;--g:linear-gradient(135deg,#34d399,#0f766e)"></span>
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#a78bfa,#6d28d9)"></span>
</div>
<div class="mqs-09__group" style="--speed:48s">
<span class="mqs-09__tile" style="width:220px;--g:linear-gradient(135deg,#f472b6,#c026d3)"></span>
<span class="mqs-09__tile" style="width:150px;--g:linear-gradient(135deg,#38bdf8,#1d4ed8)"></span>
<span class="mqs-09__tile" style="width:260px;--g:linear-gradient(135deg,#fbbf24,#ea580c)"></span>
<span class="mqs-09__tile" style="width:170px;--g:linear-gradient(135deg,#34d399,#0f766e)"></span>
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#a78bfa,#6d28d9)"></span>
</div>
</div>
<div class="mqs-09__viewport">
<div class="mqs-09__group mqs-09__group--rev" style="--speed:62s">
<span class="mqs-09__tile" style="width:180px;--g:linear-gradient(135deg,#fb7185,#be123c)"></span>
<span class="mqs-09__tile" style="width:240px;--g:linear-gradient(135deg,#4ade80,#15803d)"></span>
<span class="mqs-09__tile" style="width:140px;--g:linear-gradient(135deg,#facc15,#a16207)"></span>
<span class="mqs-09__tile" style="width:210px;--g:linear-gradient(135deg,#22d3ee,#0e7490)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#c084fc,#7e22ce)"></span>
</div>
<div class="mqs-09__group mqs-09__group--rev" style="--speed:62s">
<span class="mqs-09__tile" style="width:180px;--g:linear-gradient(135deg,#fb7185,#be123c)"></span>
<span class="mqs-09__tile" style="width:240px;--g:linear-gradient(135deg,#4ade80,#15803d)"></span>
<span class="mqs-09__tile" style="width:140px;--g:linear-gradient(135deg,#facc15,#a16207)"></span>
<span class="mqs-09__tile" style="width:210px;--g:linear-gradient(135deg,#22d3ee,#0e7490)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#c084fc,#7e22ce)"></span>
</div>
</div>
<div class="mqs-09__viewport">
<div class="mqs-09__group" style="--speed:55s">
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#818cf8,#3730a3)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#f97316,#9a3412)"></span>
<span class="mqs-09__tile" style="width:250px;--g:linear-gradient(135deg,#2dd4bf,#115e59)"></span>
<span class="mqs-09__tile" style="width:145px;--g:linear-gradient(135deg,#e879f9,#a21caf)"></span>
<span class="mqs-09__tile" style="width:190px;--g:linear-gradient(135deg,#94a3b8,#334155)"></span>
</div>
<div class="mqs-09__group" style="--speed:55s">
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#818cf8,#3730a3)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#f97316,#9a3412)"></span>
<span class="mqs-09__tile" style="width:250px;--g:linear-gradient(135deg,#2dd4bf,#115e59)"></span>
<span class="mqs-09__tile" style="width:145px;--g:linear-gradient(135deg,#e879f9,#a21caf)"></span>
<span class="mqs-09__tile" style="width:190px;--g:linear-gradient(135deg,#94a3b8,#334155)"></span>
</div>
</div>
</div>
<div class="mqs-09__fore">
<h3 class="mqs-09__hero">Made with the brands you love</h3>
<p class="mqs-09__sub">Swap the gradient tiles for campaign imagery — the wall is pure decoration, invisible to screen readers.</p>
</div>
</section>.mqs-09,
.mqs-09 *,
.mqs-09 *::before,
.mqs-09 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.mqs-09 {
width: 100%;
--gap: 18px;
position: relative;
font-family: 'Segoe UI',system-ui,sans-serif;
background: #09090b;
overflow: hidden;
min-height: 100vh;
display: grid;
}
.mqs-09__wall {
position: absolute;
inset: -30px 0;
display: flex;
flex-direction: column;
justify-content: center;
gap: var(--gap);
}
.mqs-09__viewport {
display: flex;
gap: var(--gap);
overflow: hidden;
}
.mqs-09__group {
flex: none;
display: flex;
gap: var(--gap);
animation: mqs-09-scroll var(--speed) linear infinite;
will-change: transform;
}
.mqs-09__group--rev {
animation-direction: reverse;
}
@keyframes mqs-09-scroll {
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
.mqs-09__tile {
flex: none;
aspect-ratio: 3/2;
border-radius: 14px;
background: var(--g);
opacity: .8;
}
.mqs-09__tile:nth-child(odd) {
rotate: 1.2deg;
}
.mqs-09__tile:nth-child(even) {
rotate: -1.2deg;
}
.mqs-09__fore {
position: relative;
z-index: 1;
display: grid;
place-content: center;
gap: 12px;
text-align: center;
padding: 64px 24px;
background: radial-gradient(ellipse 70% 80% at 50% 50%,rgba(9,9,11,.92) 30%,rgba(9,9,11,.55) 70%,rgba(9,9,11,.25));
}
.mqs-09__hero {
font-size: clamp(26px,5vw,44px);
font-weight: 800;
color: #fafafa;
letter-spacing: -.03em;
text-wrap: balance;
}
.mqs-09__sub {
font-size: 14px;
color: #a1a1aa;
max-width: 52ch;
margin-inline: auto;
text-wrap: pretty;
}
@media (prefers-reduced-motion: reduce) {
.mqs-09__group {
animation: none;
}
}.mqs-09,
.mqs-09 *,
.mqs-09 *::before,
.mqs-09 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.mqs-09 {
width: 100%;
--gap: 18px;
position: relative;
font-family: 'Segoe UI',system-ui,sans-serif;
background: #09090b;
overflow: hidden;
min-height: 100vh;
display: grid;
}
.mqs-09__wall {
position: absolute;
inset: -30px 0;
display: flex;
flex-direction: column;
justify-content: center;
gap: var(--gap);
}
.mqs-09__viewport {
display: flex;
gap: var(--gap);
overflow: hidden;
}
.mqs-09__group {
flex: none;
display: flex;
gap: var(--gap);
animation: mqs-09-scroll var(--speed) linear infinite;
will-change: transform;
}
.mqs-09__group--rev {
animation-direction: reverse;
}
@keyframes mqs-09-scroll {
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
.mqs-09__tile {
flex: none;
aspect-ratio: 3/2;
border-radius: 14px;
background: var(--g);
opacity: .8;
}
.mqs-09__tile:nth-child(odd) {
rotate: 1.2deg;
}
.mqs-09__tile:nth-child(even) {
rotate: -1.2deg;
}
.mqs-09__fore {
position: relative;
z-index: 1;
display: grid;
place-content: center;
gap: 12px;
text-align: center;
padding: 64px 24px;
background: radial-gradient(ellipse 70% 80% at 50% 50%,rgba(9,9,11,.92) 30%,rgba(9,9,11,.55) 70%,rgba(9,9,11,.25));
}
.mqs-09__hero {
font-size: clamp(26px,5vw,44px);
font-weight: 800;
color: #fafafa;
letter-spacing: -.03em;
text-wrap: balance;
}
.mqs-09__sub {
font-size: 14px;
color: #a1a1aa;
max-width: 52ch;
margin-inline: auto;
text-wrap: pretty;
}
@media (prefers-reduced-motion: reduce) {
.mqs-09__group {
animation: none;
}
}/* No JavaScript — three counter-phased rows (--speed + animation-direction each) create the faux-parallax depth; the wall is aria-hidden decoration behind a scrim. */
/* No JavaScript — three counter-phased rows (--speed + animation-direction each) create the faux-parallax depth; the wall is aria-hidden decoration behind a scrim. */Here's a working CSS Infinite Marquee Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Image-Heavy Brand Wall — Multi-Row Masonry Marquee Background
Source: https://codefronts.com/motion/css-infinite-marquee/image-brand-wall-multi-row-marquee/
A full-bleed, three-row wall of mixed-width imagery drifting at three different speeds and directions — the 'living moodboard' agencies and creator brands run behind hero copy. Rows use varied tile widths and subtle tilts so it reads masonry, a dark scrim keeps foreground text at AAA contrast, and the whole wall is aria-hidden because it is decoration by design.
## HTML
```html
<section class="mqs-09" aria-label="Image brand wall marquee demo">
<div class="mqs-09__wall" aria-hidden="true">
<div class="mqs-09__viewport">
<div class="mqs-09__group" style="--speed:48s">
<span class="mqs-09__tile" style="width:220px;--g:linear-gradient(135deg,#f472b6,#c026d3)"></span>
<span class="mqs-09__tile" style="width:150px;--g:linear-gradient(135deg,#38bdf8,#1d4ed8)"></span>
<span class="mqs-09__tile" style="width:260px;--g:linear-gradient(135deg,#fbbf24,#ea580c)"></span>
<span class="mqs-09__tile" style="width:170px;--g:linear-gradient(135deg,#34d399,#0f766e)"></span>
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#a78bfa,#6d28d9)"></span>
</div>
<div class="mqs-09__group" style="--speed:48s">
<span class="mqs-09__tile" style="width:220px;--g:linear-gradient(135deg,#f472b6,#c026d3)"></span>
<span class="mqs-09__tile" style="width:150px;--g:linear-gradient(135deg,#38bdf8,#1d4ed8)"></span>
<span class="mqs-09__tile" style="width:260px;--g:linear-gradient(135deg,#fbbf24,#ea580c)"></span>
<span class="mqs-09__tile" style="width:170px;--g:linear-gradient(135deg,#34d399,#0f766e)"></span>
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#a78bfa,#6d28d9)"></span>
</div>
</div>
<div class="mqs-09__viewport">
<div class="mqs-09__group mqs-09__group--rev" style="--speed:62s">
<span class="mqs-09__tile" style="width:180px;--g:linear-gradient(135deg,#fb7185,#be123c)"></span>
<span class="mqs-09__tile" style="width:240px;--g:linear-gradient(135deg,#4ade80,#15803d)"></span>
<span class="mqs-09__tile" style="width:140px;--g:linear-gradient(135deg,#facc15,#a16207)"></span>
<span class="mqs-09__tile" style="width:210px;--g:linear-gradient(135deg,#22d3ee,#0e7490)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#c084fc,#7e22ce)"></span>
</div>
<div class="mqs-09__group mqs-09__group--rev" style="--speed:62s">
<span class="mqs-09__tile" style="width:180px;--g:linear-gradient(135deg,#fb7185,#be123c)"></span>
<span class="mqs-09__tile" style="width:240px;--g:linear-gradient(135deg,#4ade80,#15803d)"></span>
<span class="mqs-09__tile" style="width:140px;--g:linear-gradient(135deg,#facc15,#a16207)"></span>
<span class="mqs-09__tile" style="width:210px;--g:linear-gradient(135deg,#22d3ee,#0e7490)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#c084fc,#7e22ce)"></span>
</div>
</div>
<div class="mqs-09__viewport">
<div class="mqs-09__group" style="--speed:55s">
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#818cf8,#3730a3)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#f97316,#9a3412)"></span>
<span class="mqs-09__tile" style="width:250px;--g:linear-gradient(135deg,#2dd4bf,#115e59)"></span>
<span class="mqs-09__tile" style="width:145px;--g:linear-gradient(135deg,#e879f9,#a21caf)"></span>
<span class="mqs-09__tile" style="width:190px;--g:linear-gradient(135deg,#94a3b8,#334155)"></span>
</div>
<div class="mqs-09__group" style="--speed:55s">
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#818cf8,#3730a3)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#f97316,#9a3412)"></span>
<span class="mqs-09__tile" style="width:250px;--g:linear-gradient(135deg,#2dd4bf,#115e59)"></span>
<span class="mqs-09__tile" style="width:145px;--g:linear-gradient(135deg,#e879f9,#a21caf)"></span>
<span class="mqs-09__tile" style="width:190px;--g:linear-gradient(135deg,#94a3b8,#334155)"></span>
</div>
</div>
</div>
<div class="mqs-09__fore">
<h3 class="mqs-09__hero">Made with the brands you love</h3>
<p class="mqs-09__sub">Swap the gradient tiles for campaign imagery — the wall is pure decoration, invisible to screen readers.</p>
</div>
</section>
```
## CSS
```css
.mqs-09,
.mqs-09 *,
.mqs-09 *::before,
.mqs-09 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.mqs-09 {
width: 100%;
--gap: 18px;
position: relative;
font-family: 'Segoe UI',system-ui,sans-serif;
background: #09090b;
overflow: hidden;
min-height: 100vh;
display: grid;
}
.mqs-09__wall {
position: absolute;
inset: -30px 0;
display: flex;
flex-direction: column;
justify-content: center;
gap: var(--gap);
}
.mqs-09__viewport {
display: flex;
gap: var(--gap);
overflow: hidden;
}
.mqs-09__group {
flex: none;
display: flex;
gap: var(--gap);
animation: mqs-09-scroll var(--speed) linear infinite;
will-change: transform;
}
.mqs-09__group--rev {
animation-direction: reverse;
}
@keyframes mqs-09-scroll {
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
.mqs-09__tile {
flex: none;
aspect-ratio: 3/2;
border-radius: 14px;
background: var(--g);
opacity: .8;
}
.mqs-09__tile:nth-child(odd) {
rotate: 1.2deg;
}
.mqs-09__tile:nth-child(even) {
rotate: -1.2deg;
}
.mqs-09__fore {
position: relative;
z-index: 1;
display: grid;
place-content: center;
gap: 12px;
text-align: center;
padding: 64px 24px;
background: radial-gradient(ellipse 70% 80% at 50% 50%,rgba(9,9,11,.92) 30%,rgba(9,9,11,.55) 70%,rgba(9,9,11,.25));
}
.mqs-09__hero {
font-size: clamp(26px,5vw,44px);
font-weight: 800;
color: #fafafa;
letter-spacing: -.03em;
text-wrap: balance;
}
.mqs-09__sub {
font-size: 14px;
color: #a1a1aa;
max-width: 52ch;
margin-inline: auto;
text-wrap: pretty;
}
@media (prefers-reduced-motion: reduce) {
.mqs-09__group {
animation: none;
}
}
```
## JavaScript
```js
/* No JavaScript — three counter-phased rows (--speed + animation-direction each) create the faux-parallax depth; the wall is aria-hidden decoration behind a scrim. */
```Here's a working CSS Infinite Marquee Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Image-Heavy Brand Wall — Multi-Row Masonry Marquee Background
Source: https://codefronts.com/motion/css-infinite-marquee/image-brand-wall-multi-row-marquee/
A full-bleed, three-row wall of mixed-width imagery drifting at three different speeds and directions — the 'living moodboard' agencies and creator brands run behind hero copy. Rows use varied tile widths and subtle tilts so it reads masonry, a dark scrim keeps foreground text at AAA contrast, and the whole wall is aria-hidden because it is decoration by design.
## HTML
```html
<section class="mqs-09" aria-label="Image brand wall marquee demo">
<div class="mqs-09__wall" aria-hidden="true">
<div class="mqs-09__viewport">
<div class="mqs-09__group" style="--speed:48s">
<span class="mqs-09__tile" style="width:220px;--g:linear-gradient(135deg,#f472b6,#c026d3)"></span>
<span class="mqs-09__tile" style="width:150px;--g:linear-gradient(135deg,#38bdf8,#1d4ed8)"></span>
<span class="mqs-09__tile" style="width:260px;--g:linear-gradient(135deg,#fbbf24,#ea580c)"></span>
<span class="mqs-09__tile" style="width:170px;--g:linear-gradient(135deg,#34d399,#0f766e)"></span>
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#a78bfa,#6d28d9)"></span>
</div>
<div class="mqs-09__group" style="--speed:48s">
<span class="mqs-09__tile" style="width:220px;--g:linear-gradient(135deg,#f472b6,#c026d3)"></span>
<span class="mqs-09__tile" style="width:150px;--g:linear-gradient(135deg,#38bdf8,#1d4ed8)"></span>
<span class="mqs-09__tile" style="width:260px;--g:linear-gradient(135deg,#fbbf24,#ea580c)"></span>
<span class="mqs-09__tile" style="width:170px;--g:linear-gradient(135deg,#34d399,#0f766e)"></span>
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#a78bfa,#6d28d9)"></span>
</div>
</div>
<div class="mqs-09__viewport">
<div class="mqs-09__group mqs-09__group--rev" style="--speed:62s">
<span class="mqs-09__tile" style="width:180px;--g:linear-gradient(135deg,#fb7185,#be123c)"></span>
<span class="mqs-09__tile" style="width:240px;--g:linear-gradient(135deg,#4ade80,#15803d)"></span>
<span class="mqs-09__tile" style="width:140px;--g:linear-gradient(135deg,#facc15,#a16207)"></span>
<span class="mqs-09__tile" style="width:210px;--g:linear-gradient(135deg,#22d3ee,#0e7490)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#c084fc,#7e22ce)"></span>
</div>
<div class="mqs-09__group mqs-09__group--rev" style="--speed:62s">
<span class="mqs-09__tile" style="width:180px;--g:linear-gradient(135deg,#fb7185,#be123c)"></span>
<span class="mqs-09__tile" style="width:240px;--g:linear-gradient(135deg,#4ade80,#15803d)"></span>
<span class="mqs-09__tile" style="width:140px;--g:linear-gradient(135deg,#facc15,#a16207)"></span>
<span class="mqs-09__tile" style="width:210px;--g:linear-gradient(135deg,#22d3ee,#0e7490)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#c084fc,#7e22ce)"></span>
</div>
</div>
<div class="mqs-09__viewport">
<div class="mqs-09__group" style="--speed:55s">
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#818cf8,#3730a3)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#f97316,#9a3412)"></span>
<span class="mqs-09__tile" style="width:250px;--g:linear-gradient(135deg,#2dd4bf,#115e59)"></span>
<span class="mqs-09__tile" style="width:145px;--g:linear-gradient(135deg,#e879f9,#a21caf)"></span>
<span class="mqs-09__tile" style="width:190px;--g:linear-gradient(135deg,#94a3b8,#334155)"></span>
</div>
<div class="mqs-09__group" style="--speed:55s">
<span class="mqs-09__tile" style="width:200px;--g:linear-gradient(135deg,#818cf8,#3730a3)"></span>
<span class="mqs-09__tile" style="width:160px;--g:linear-gradient(135deg,#f97316,#9a3412)"></span>
<span class="mqs-09__tile" style="width:250px;--g:linear-gradient(135deg,#2dd4bf,#115e59)"></span>
<span class="mqs-09__tile" style="width:145px;--g:linear-gradient(135deg,#e879f9,#a21caf)"></span>
<span class="mqs-09__tile" style="width:190px;--g:linear-gradient(135deg,#94a3b8,#334155)"></span>
</div>
</div>
</div>
<div class="mqs-09__fore">
<h3 class="mqs-09__hero">Made with the brands you love</h3>
<p class="mqs-09__sub">Swap the gradient tiles for campaign imagery — the wall is pure decoration, invisible to screen readers.</p>
</div>
</section>
```
## CSS
```css
.mqs-09,
.mqs-09 *,
.mqs-09 *::before,
.mqs-09 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.mqs-09 {
width: 100%;
--gap: 18px;
position: relative;
font-family: 'Segoe UI',system-ui,sans-serif;
background: #09090b;
overflow: hidden;
min-height: 100vh;
display: grid;
}
.mqs-09__wall {
position: absolute;
inset: -30px 0;
display: flex;
flex-direction: column;
justify-content: center;
gap: var(--gap);
}
.mqs-09__viewport {
display: flex;
gap: var(--gap);
overflow: hidden;
}
.mqs-09__group {
flex: none;
display: flex;
gap: var(--gap);
animation: mqs-09-scroll var(--speed) linear infinite;
will-change: transform;
}
.mqs-09__group--rev {
animation-direction: reverse;
}
@keyframes mqs-09-scroll {
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
.mqs-09__tile {
flex: none;
aspect-ratio: 3/2;
border-radius: 14px;
background: var(--g);
opacity: .8;
}
.mqs-09__tile:nth-child(odd) {
rotate: 1.2deg;
}
.mqs-09__tile:nth-child(even) {
rotate: -1.2deg;
}
.mqs-09__fore {
position: relative;
z-index: 1;
display: grid;
place-content: center;
gap: 12px;
text-align: center;
padding: 64px 24px;
background: radial-gradient(ellipse 70% 80% at 50% 50%,rgba(9,9,11,.92) 30%,rgba(9,9,11,.55) 70%,rgba(9,9,11,.25));
}
.mqs-09__hero {
font-size: clamp(26px,5vw,44px);
font-weight: 800;
color: #fafafa;
letter-spacing: -.03em;
text-wrap: balance;
}
.mqs-09__sub {
font-size: 14px;
color: #a1a1aa;
max-width: 52ch;
margin-inline: auto;
text-wrap: pretty;
}
@media (prefers-reduced-motion: reduce) {
.mqs-09__group {
animation: none;
}
}
```
## JavaScript
```js
/* No JavaScript — three counter-phased rows (--speed + animation-direction each) create the faux-parallax depth; the wall is aria-hidden decoration behind a scrim. */
```How this works
Three stacked marquee rows, each with its own --speed and alternating animation-direction, create parallax-like depth: the eye reads different speeds as different distances. Tiles are aspect-ratio-driven boxes of varied widths (140–260px) so each row has a broken, masonry-ish rhythm rather than a grid march; alternate tiles carry a ±1.2deg rotation for a hand-placed feel.
This demo ships with gradient placeholder tiles — swap each tile's background for <img loading="lazy" alt=""> or a CSS background-image. Because tiles declare aspect-ratio + explicit width, the track width is stable BEFORE any image loads: zero CLS and no loop desync while images stream in.
The whole wall is aria-hidden="true" and sits behind a foreground layer with a scrim gradient — the correct architecture when a marquee is ambience: screen readers skip it entirely, the hero copy on top stays ≥7:1 contrast, and prefers-reduced-motion simply freezes the wall into a static collage (nothing scrolls, nothing is lost, the vibe survives).
Techniques used: three counter-phased rows (--speed + animation-direction per row) for faux parallax · aspect-ratio + fixed widths for CLS-free image slots · alternating micro-rotations for masonry feel · aria-hidden decorative layer + scrim overlay for text contrast · reduced-motion freeze (static collage, not removal)
Make it yours
- Swap tiles for real images:
<img src loading="lazy" alt="" class="mqs-09__img">inside each tile — keep alt empty, the wall is decorative. - Depth illusion: keep row speeds ~25% apart (48s / 62s / 55s here); equal speeds flatten it instantly.
- Tilt amount: the ±1.2deg on nth-child rules — 0 for corporate, up to 3deg for scrapbook.
- Scrim strength: the rgba stops in the overlay gradient; check your headline still hits 4.5:1 minimum.
Gotchas — read before shipping
- Decorative walls must be aria-hidden AND contain no focusable elements — an
<a>inside an aria-hidden wall is a broken tab stop (focusable but silent). - Give every image slot aspect-ratio + width BEFORE the image loads, or the loop desyncs as tracks change width mid-animation.
- Three animated rows of images is real GPU work — keep tiles ≤300px wide, compress images (AVIF/WebP), and never run this behind another animation-heavy section.
- Don't put critical brand names ONLY in the wall; it's invisible to assistive tech by design.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by text-wrap as this demo is written. The core technique itself goes back further — Chrome all.
aspect-ratio is baseline since 2021; everything else is plain CSS animation. Degrades to static collage under reduced motion by design.