{ CF }

12 CSS Scroll Animations

Parallax Cosmos

A 320vh sticky scene with six depth layers and a canvas starfield drifting at independent speeds, depth labels, and a scroll-progress bar.

CSS + JS MIT licensed

Parallax Cosmos the 1st 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.

Open in playground

The code

<div class="prog" id="prog"></div>
<div id="pw">
  <div id="pi">
    <canvas id="cv"></canvas>
    <div class="ly" id="l-r3"><div class="ring r3"></div></div>
    <div class="ly" id="l-r2"><div class="ring r2"></div></div>
    <div class="ly" id="l-orb"><div class="orb"></div></div>
    <div class="ly" id="l-r1"><div class="ring r1"></div></div>
    <div class="ly" id="l-ghost"><div class="ghost">DEPTH</div></div>
    <div class="ly" id="l-tag"><div class="tagline">Scroll to feel the layers</div></div>
    <div class="dot d1" id="dot1"></div>
    <div class="dot d2" id="dot2"></div>
    <div class="dot d3" id="dot3"></div>
    <div class="depth-label a1" id="lbl1">01 — Atmosphere</div>
    <div class="depth-label a2" id="lbl2">02 — Orbit</div>
    <div class="depth-label a3" id="lbl3">03 — Core</div>
  </div>
</div>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
body{background:#04040B;overflow-x:hidden}
#pw{height:320vh;position:relative}
#pi{
  position:sticky;top:0;height:100vh;overflow:hidden;
  background:#04040B;display:flex;align-items:center;justify-content:center;
}
canvas{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.ly{
  position:absolute;inset:0;
  display:flex;align-items:center;justify-content:center;
  will-change:transform;pointer-events:none;
}
.ghost{
  font-family:'Bebas Neue',sans-serif;
  font-size:clamp(100px,17vw,250px);
  color:transparent;
  -webkit-text-stroke:1px rgba(201,169,110,0.11);
  letter-spacing:0.05em;user-select:none;white-space:nowrap;
}
.orb{
  width:clamp(320px,46vw,580px);height:clamp(320px,46vw,580px);
  border-radius:50%;
  background:radial-gradient(circle at 38% 34%,rgba(201,169,110,0.16),rgba(140,80,220,0.05) 48%,transparent 72%);
}
.ring{border-radius:50%;border:1px solid rgba(201,169,110,0.07)}
.r1{width:clamp(200px,33vw,430px);height:clamp(200px,33vw,430px)}
.r2{width:clamp(450px,72vw,840px);height:clamp(450px,72vw,840px);border-color:rgba(201,169,110,0.04)}
.r3{width:clamp(520px,88vw,1020px);height:clamp(520px,88vw,1020px);border-color:rgba(201,169,110,0.025)}
.tagline{
  font-family:'Fraunces',serif;font-style:italic;
  font-size:clamp(16px,2.2vw,28px);
  color:rgba(201,169,110,0.72);text-align:center;
  white-space:nowrap;
}
.dot{
  width:3px;height:3px;border-radius:50%;background:#C9A96E;
  box-shadow:0 0 14px 5px rgba(201,169,110,0.22);
}
.d1{position:absolute;top:30%;right:24%}
.d2{position:absolute;bottom:26%;left:20%}
.d3{position:absolute;top:58%;right:17%}

/* scroll progress */
.prog{
  position:fixed;bottom:0;left:0;height:1px;
  background:linear-gradient(to right,#C9A96E 0%,rgba(201,169,110,0.15) 100%);
  width:0%;z-index:100;transition:width 0.08s linear;
}
/* depth labels */
.depth-label{
  position:absolute;
  font-family:'Fraunces',serif;font-style:italic;
  font-size:clamp(11px,1.2vw,15px);
  color:rgba(201,169,110,0.0);
  letter-spacing:0.1em;
  transition:color 0.6s ease;
}
.depth-label.a1{top:18%;left:8%}
.depth-label.a2{bottom:20%;right:9%}
.depth-label.a3{top:50%;left:50%;transform:translate(-50%,-50%)}
const cv = document.getElementById('cv');
const ctx = cv.getContext('2d');
function drawStars(){
  cv.width = window.innerWidth;
  cv.height = window.innerHeight;
  ctx.clearRect(0,0,cv.width,cv.height);
  for(let i=0;i<280;i++){
    const x=Math.random()*cv.width, y=Math.random()*cv.height;
    const r=Math.random()*1.5+0.15;
    ctx.beginPath();ctx.arc(x,y,r,0,Math.PI*2);
    ctx.fillStyle=`rgba(255,252,215,${Math.random()*0.55+0.07})`;
    ctx.fill();
  }
  for(let i=0;i<12;i++){
    const x=Math.random()*cv.width, y=Math.random()*cv.height;
    ctx.beginPath();ctx.arc(x,y,1.8,0,Math.PI*2);
    ctx.fillStyle='rgba(255,250,200,0.75)';ctx.fill();
  }
}
drawStars();
window.addEventListener('resize',drawStars);

const pw = document.getElementById('pw');
const prog = document.getElementById('prog');
const layers = [
  {el:document.getElementById('l-r3'),  range:60},
  {el:document.getElementById('l-r2'),  range:110},
  {el:document.getElementById('l-orb'), range:180},
  {el:document.getElementById('l-r1'),  range:270},
  {el:document.getElementById('l-ghost'),range:480},
  {el:document.getElementById('l-tag'), range:90},
];

const lbl1=document.getElementById('lbl1');
const lbl2=document.getElementById('lbl2');
const lbl3=document.getElementById('lbl3');

window.addEventListener('scroll',()=>{
  const rect = pw.getBoundingClientRect();
  const scrolled = -rect.top;
  const maxScroll = pw.offsetHeight - window.innerHeight;
  const p = Math.max(0,Math.min(1, scrolled/maxScroll));

  prog.style.width = (p*100)+'%';

  layers.forEach(l=>{
    const offset = (p - 0.5) * l.range;
    l.el.style.transform = `translateY(${offset}px)`;
  });

  lbl1.style.color = p > 0.15 ? `rgba(201,169,110,${Math.min((p-0.15)*4,0.45)})` : 'rgba(201,169,110,0)';
  lbl2.style.color = p > 0.45 ? `rgba(201,169,110,${Math.min((p-0.45)*4,0.45)})` : 'rgba(201,169,110,0)';
  lbl3.style.color = p > 0.72 ? `rgba(201,169,110,${Math.min((p-0.72)*4,0.45)})` : 'rgba(201,169,110,0)';

  document.getElementById('l-ghost').firstElementChild.style.webkitTextStroke =
    `1px rgba(201,169,110,${0.06 + p * 0.22})`;
},{passive:true});

Search CodeFronts

Loading…