Staggered Portfolio List
A work index whose rows arrive one at a time with a staggered slide-up, plus a hover sweep and arrow nudge.
Staggered Portfolio List the 9th of 12 designs in the 12 CSS Scroll Animations collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.
Live preview
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<header>
<div class="kicker">Selected Work — 2019 / 2026</div>
<h1>A list that arrives one row at a time.</h1>
</header>
<div class="list" id="list">
<div class="item">
<span class="idx">01</span>
<div class="mid"><span class="title">Halcyon Identity System</span><span class="meta">Branding · Art Direction</span></div>
<div class="right"><span class="year">2026</span><span class="arrow">↗</span></div>
</div>
<div class="item">
<span class="idx">02</span>
<div class="mid"><span class="title">Northwind Commerce Platform</span><span class="meta">Product Design · Engineering</span></div>
<div class="right"><span class="year">2025</span><span class="arrow">↗</span></div>
</div>
<div class="item">
<span class="idx">03</span>
<div class="mid"><span class="title">Atlas Editorial Redesign</span><span class="meta">Web · Typography</span></div>
<div class="right"><span class="year">2025</span><span class="arrow">↗</span></div>
</div>
<div class="item">
<span class="idx">04</span>
<div class="mid"><span class="title">Lumen Motion Library</span><span class="meta">Animation · Systems</span></div>
<div class="right"><span class="year">2024</span><span class="arrow">↗</span></div>
</div>
<div class="item">
<span class="idx">05</span>
<div class="mid"><span class="title">Verdant Sustainability Report</span><span class="meta">Data Viz · Layout</span></div>
<div class="right"><span class="year">2023</span><span class="arrow">↗</span></div>
</div>
<div class="item">
<span class="idx">06</span>
<div class="mid"><span class="title">Strata Mobile Banking</span><span class="meta">UX · Prototyping</span></div>
<div class="right"><span class="year">2022</span><span class="arrow">↗</span></div>
</div>
<div class="item">
<span class="idx">07</span>
<div class="mid"><span class="title">Cinder Festival Campaign</span><span class="meta">Brand · Print</span></div>
<div class="right"><span class="year">2021</span><span class="arrow">↗</span></div>
</div>
<div class="item">
<span class="idx">08</span>
<div class="mid"><span class="title">Orbit Developer Portal</span><span class="meta">Docs · Information Design</span></div>
<div class="right"><span class="year">2019</span><span class="arrow">↗</span></div>
</div>
</div> *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
body{background:#0B0B0C;color:#EDEDED;font-family:'Bricolage Grotesque',sans-serif;overflow-x:hidden}
header{
padding:8rem 6vw 4rem;
}
.kicker{
font-family:'JetBrains Mono',monospace;font-size:11px;
letter-spacing:0.2em;text-transform:uppercase;
color:#7C7C82;margin-bottom:1.5rem;
}
header h1{
font-size:clamp(38px,6vw,76px);font-weight:800;
line-height:1;letter-spacing:-0.03em;max-width:14ch;
}
/* list */
.list{padding:2rem 6vw 10rem}
.item{
display:grid;
grid-template-columns:64px 1fr auto;
align-items:center;gap:2rem;
padding:2.4rem 0;
border-top:1px solid rgba(255,255,255,0.1);
position:relative;cursor:pointer;
opacity:0;transform:translateY(46px);
transition:opacity 0.8s cubic-bezier(0.16,1,0.3,1),
transform 0.8s cubic-bezier(0.16,1,0.3,1);
}
.item.in{opacity:1;transform:none}
.item:last-child{border-bottom:1px solid rgba(255,255,255,0.1)}
.idx{
font-family:'JetBrains Mono',monospace;font-size:13px;
color:#5A5A60;
}
.mid .title{
font-size:clamp(22px,3vw,38px);font-weight:600;
letter-spacing:-0.02em;transition:transform 0.4s cubic-bezier(0.16,1,0.3,1);
}
.mid .meta{
font-family:'JetBrains Mono',monospace;font-size:12px;
color:#7C7C82;margin-top:0.5rem;
}
.year{
font-family:'JetBrains Mono',monospace;font-size:13px;
color:#7C7C82;
}
/* hover sweep */
.item::before{
content:'';position:absolute;left:-6vw;right:-6vw;top:0;bottom:0;
background:linear-gradient(90deg,transparent,rgba(124,58,237,0.12),transparent);
opacity:0;transition:opacity 0.35s;pointer-events:none;
}
.item:hover::before{opacity:1}
.item:hover .title{transform:translateX(14px)}
.item:hover .arrow{transform:translate(6px,-6px);color:#A78BFA}
.arrow{
font-size:22px;color:#5A5A60;
transition:transform 0.35s cubic-bezier(0.16,1,0.3,1),color 0.35s;
}
.mid{display:flex;flex-direction:column}
.right{display:flex;align-items:center;gap:1.6rem} const io=new IntersectionObserver((entries)=>{
entries.forEach(e=>{
if(!e.isIntersecting)return;
// stagger by index within the list
const items=[...document.querySelectorAll('.item')];
const i=items.indexOf(e.target);
e.target.style.transitionDelay=(Math.min(i,7)*0.07)+'s';
e.target.classList.add('in');
io.unobserve(e.target);
});
},{threshold:0.2});
document.querySelectorAll('.item').forEach(el=>io.observe(el));