11 CSS Page Transitions09 / 11

CSS + JSMIT licensed

Vertical Split Curtain

Two full-height panels slide closed like theatre curtains, swap the page, then split apart with a different easing — a gold-seamed theatrical reveal. A Parisian haute couture house.

Published

Live Demo
Try it

This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.

The code

<!-- Curtain panels -->
<div class="curtain-left" id="cLeft"></div>
<div class="curtain-right" id="cRight"></div>

<div class="pages">

  <div class="page active" id="p0">
    <div class="p0-layout">
      <div class="p0-left">
        <div class="p0-mark">Maison Lécluse · Paris</div>
        <div class="p0-main">
          <div class="p0-season">Automne–Hiver 2025</div>
          <h1 class="p0-title">Entre<br>Ombre<br>&amp; Lumière</h1>
          <div class="p0-title-fr">Between shadow and light</div>
          <p class="p0-body">A collection born from the silences between words. Forty-two looks. Each one a conversation the body has alone.</p>
          <button class="p0-cta" data-next="1">Discover the collection <span class="p0-cta-arrow"></span></button>
        </div>
      </div>
      <div class="p0-right">
        <div class="silhouette-area">
          <div class="figure">
            <div class="fig-head"></div>
            <div class="fig-arm fig-arm-l"></div>
            <div class="fig-arm fig-arm-r"></div>
            <div class="fig-body"></div>
          </div>
        </div>
        <div class="p0-right-bottom">
          <div class="p0-detail-row"><div class="det-key">Maison</div><div class="det-val">Since 1967</div></div>
          <div class="p0-detail-row"><div class="det-key">Ateliers</div><div class="det-val">Paris · Florence</div></div>
          <div class="p0-detail-row"><div class="det-key">Collection</div><div class="det-val">AH 2025 · 42 looks</div></div>
          <div class="p0-detail-row"><div class="det-key">Runway</div><div class="det-val">Palais Royal, 4 Oct</div></div>
        </div>
      </div>
    </div>
  </div>

  <div class="page" id="p1">
    <div class="p1-top">
      <h2 class="p1-title">The<br>Collection</h2>
      <div class="p1-count">42 Looks · AH 2025</div>
    </div>
    <div class="look-grid">
      <div class="look"><div class="look-img"><div class="garment g1"></div></div><div class="look-num">Look 01</div><div class="look-name">L'aube noire</div></div>
      <div class="look"><div class="look-img"><div class="garment g2"></div></div><div class="look-num">Look 07</div><div class="look-name">Le voile froid</div></div>
      <div class="look"><div class="look-img"><div class="garment g3"></div></div><div class="look-num">Look 14</div><div class="look-name">La colonne</div></div>
      <div class="look"><div class="look-img"><div class="garment g4"></div></div><div class="look-num">Look 21</div><div class="look-name">Le bruissement</div></div>
      <div class="look"><div class="look-img"><div class="garment g5"></div></div><div class="look-num">Look 38</div><div class="look-name">La chute</div></div>
    </div>
  </div>

  <div class="page" id="p2">
    <div class="p2-left">
      <div class="p2-eyebrow">L'Atelier Lécluse</div>
      <h2 class="p2-title">Made by<br>hand, in<br>silence</h2>
      <p class="p2-body">Each garment passes through twenty-four pairs of hands before it leaves the atelier. We consider this not a process, but a conversation with the material.</p>
      <div class="craft-list">
        <div class="craft-row"><div class="craft-n">I</div><div class="craft-t">Pattern cutting by master tailleur</div></div>
        <div class="craft-row"><div class="craft-n">II</div><div class="craft-t">Hand-draping on the mannequin</div></div>
        <div class="craft-row"><div class="craft-n">III</div><div class="craft-t">Three fittings per garment minimum</div></div>
        <div class="craft-row"><div class="craft-n">IV</div><div class="craft-t">Handstitched finishing throughout</div></div>
        <div class="craft-row"><div class="craft-n">V</div><div class="craft-t">Final inspection by the directrice</div></div>
      </div>
    </div>
    <div class="p2-right">
      <div class="maison-since">Maison Lécluse · Since 1967</div>
      <div class="p2-numbers">
        <div class="num-item"><div class="num-big">58</div><div class="num-label">Years of haute<br>couture</div></div>
        <div class="num-item"><div class="num-big">24</div><div class="num-label">Artisan hands per<br>garment</div></div>
        <div class="num-item"><div class="num-big">200+</div><div class="num-label">Hours in a single<br>couture piece</div></div>
      </div>
    </div>
  </div>

  <div class="page" id="p3">
    <div class="p3-bg-text">ML</div>
    <div class="p3-content">
      <span class="p3-mark">Maison Lécluse · Paris</span>
      <h2 class="p3-title">Private<br>Fitting</h2>
      <p class="p3-sub">By appointment only. Ateliers are open to clients for consultation from Tuesday through Saturday.</p>
      <div class="p3-contact-grid">
        <div class="p3-contact-row"><div class="p3-contact-key">Address</div><div class="p3-contact-val">24 Rue du Faubourg Saint-Honoré</div></div>
        <div class="p3-contact-row"><div class="p3-contact-key">Telephone</div><div class="p3-contact-val">+33 1 42 68 00 00</div></div>
        <div class="p3-contact-row"><div class="p3-contact-key">Fitting hours</div><div class="p3-contact-val">Mar–Sam · 10h–18h</div></div>
        <div class="p3-contact-row"><div class="p3-contact-key">Correspondence</div><div class="p3-contact-val">atelier@lecluse.paris</div></div>
      </div>
    </div>
  </div>

</div>

<!-- Nav -->
<div class="c-nav">
  <button class="c-btn" id="cPrev">‹</button>
  <div class="c-dots">
    <button class="c-dot active" data-i="0"></button>
    <button class="c-dot" data-i="1"></button>
    <button class="c-dot" data-i="2"></button>
    <button class="c-dot" data-i="3"></button>
  </div>
  <div class="c-label" id="cLabel">Maison</div>
  <button class="c-btn" id="cNext">›</button>
</div>
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  --noir: #080808;
  --white: #f8f4f0;
  --warm: #e8e0d4;
  --dim: rgba(248,244,240,0.4);
  --accent: #c8a060;
  --mid: rgba(248,244,240,0.1);
  --dur: 900ms;
  --ease: cubic-bezier(0.76,0,0.24,1);
}

html,
body {
  height: 100%;
  overflow: hidden;
  background: var(--noir);
  font-family: 'Cormorant Garamond',serif;
}
/* Pages */

.pages {
  position: fixed;
  inset: 0;
}

.page {
  position: absolute;
  inset: 0;
  pointer-events: none;
  visibility: hidden;
}

.page.active {
  visibility: visible;
  pointer-events: auto;
}
/* Curtain panels */

.curtain-left,
.curtain-right {
  position: fixed;
  top: 0;
  bottom: 0;
  z-index: 700;
  background: var(--noir);
  will-change: transform;
}

.curtain-left {
  left: 0;
  width: 50%;
  transform: translateX(-100%);
  transform-origin: left;
}

.curtain-right {
  right: 0;
  width: 50%;
  transform: translateX(100%);
  transform-origin: right;
}
/* Centre seam line */

.curtain-left::after {
  content: '';
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: linear-gradient(180deg,transparent,var(--accent),transparent);
  opacity: 0;
}
/* States */

.curtain-left.close {
  transform: translateX(0);
}

.curtain-right.close {
  transform: translateX(0);
}

.curtain-left.close::after {
  opacity: 0.4;
}
/* PAGE 0 — MAISON */

#p0 {
  background: var(--noir);
  color: var(--white);
}

.p0-layout {
  height: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.p0-left {
  padding: 60px 80px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  border-right: 1px solid var(--mid);
}

.p0-mark {
  font-family: 'Italiana',serif;
  font-size: 11px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--dim);
}

.p0-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-bottom: 20px;
}

.p0-season {
  font-size: 8px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 24px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.p0-season::before {
  content: '';
  width: 20px;
  height: 1px;
  background: var(--accent);
}

.p0-title {
  font-family: 'Italiana',serif;
  font-size: clamp(52px,8vw,112px);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--white);
  margin-bottom: 24px;
}

.p0-title-fr {
  font-size: clamp(24px,3.5vw,48px);
  font-style: italic;
  font-weight: 300;
  color: rgba(248,244,240,0.35);
  margin-bottom: 40px;
}

.p0-body {
  font-size: 13px;
  line-height: 1.9;
  font-weight: 300;
  color: var(--dim);
  max-width: 380px;
  font-style: italic;
}

.p0-cta {
  margin-top: 40px;
  display: inline-flex;
  align-items: center;
  gap: 16px;
  font-size: 9px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--white);
  cursor: pointer;
  background: none;
  border: none;
  font-family: 'Didact Gothic',sans-serif;
  transition: color .2s;
}

.p0-cta:hover {
  color: var(--accent);
}

.p0-cta-arrow {
  width: 40px;
  height: 1px;
  background: currentColor;
  transition: width .3s;
  position: relative;
}

.p0-cta-arrow::after {
  content: '';
  position: absolute;
  right: -1px;
  top: -3px;
  width: 7px;
  height: 7px;
  border-right: 1px solid currentColor;
  border-top: 1px solid currentColor;
  transform: rotate(45deg);
}

.p0-cta:hover .p0-cta-arrow {
  width: 64px;
}

.p0-right {
  display: grid;
  grid-template-rows: 1fr 1fr;
  padding: 60px;
  gap: 0;
}
/* Abstract fashion illustration using CSS shapes */

.silhouette-area {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.figure {
  position: relative;
  width: 80px;
  height: 200px;
}

.fig-body {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 48px;
  height: 140px;
  background: linear-gradient(180deg,rgba(200,160,96,0.2),rgba(200,160,96,0.06));
  border: 1px solid rgba(200,160,96,0.2);
  border-radius: 2px 2px 0 0;
}

.fig-head {
  position: absolute;
  bottom: 136px;
  left: 50%;
  transform: translateX(-50%);
  width: 20px;
  height: 24px;
  border-radius: 50%;
  background: rgba(200,160,96,0.15);
  border: 1px solid rgba(200,160,96,0.2);
}

.fig-arm {
  position: absolute;
  height: 1px;
  background: rgba(200,160,96,0.25);
  top: 72px;
}

.fig-arm-l {
  width: 32px;
  right: 48px;
}

.fig-arm-r {
  width: 32px;
  left: 48px;
}

.p0-right-bottom {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 16px;
}

.p0-detail-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  border-bottom: 1px solid var(--mid);
  padding: 12px 0;
}

.det-key {
  font-size: 8px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: rgba(248,244,240,0.25);
  font-family: 'Didact Gothic',sans-serif;
}

.det-val {
  font-size: 12px;
  font-style: italic;
  color: rgba(248,244,240,0.6);
}
/* PAGE 1 — COLLECTION */

#p1 {
  background: #0c0c0c;
  color: var(--white);
  padding: 60px 80px;
  display: flex;
  flex-direction: column;
}

.p1-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 52px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--mid);
}

.p1-title {
  font-family: 'Italiana',serif;
  font-size: clamp(44px,7vw,100px);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: -0.02em;
}

.p1-count {
  font-size: 9px;
  letter-spacing: 0.25em;
  color: var(--dim);
  font-family: 'Didact Gothic',sans-serif;
  text-transform: uppercase;
}

.look-grid {
  display: grid;
  grid-template-columns: repeat(5,1fr);
  gap: 12px;
  flex: 1;
}

.look {
  display: flex;
  flex-direction: column;
  gap: 12px;
  cursor: pointer;
}

.look-img {
  flex: 1;
  border: 1px solid rgba(248,244,240,0.06);
  position: relative;
  overflow: hidden;
  min-height: 200px;
  background: linear-gradient(180deg,#111,#0a0a0a);
  transition: border-color .3s;
}

.look:hover .look-img {
  border-color: rgba(200,160,96,0.3);
}
/* Abstract garment shape */

.garment {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 60%;
  background: rgba(200,160,96,0.08);
  border-top: 1px solid rgba(200,160,96,0.15);
}

.g1 {
  height: 70%;
  border-radius: 2px 2px 0 0;
}

.g2 {
  height: 85%;
  clip-path: polygon(20% 0,80% 0,100% 100%,0 100%);
}

.g3 {
  height: 60%;
  border-radius: 40% 40% 0 0;
}

.g4 {
  height: 75%;
  clip-path: polygon(0 0,100% 0,90% 100%,10% 100%);
}

.g5 {
  height: 90%;
  clip-path: polygon(30% 0,70% 0,100% 100%,0 100%);
}

.look-num {
  font-size: 8px;
  letter-spacing: 0.2em;
  color: var(--accent);
  font-family: 'Didact Gothic',sans-serif;
}

.look-name {
  font-family: 'Cormorant Garamond',serif;
  font-size: 13px;
  font-style: italic;
  color: rgba(248,244,240,0.7);
}
/* PAGE 2 — ATELIER */

#p2 {
  background: var(--white);
  color: var(--noir);
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.p2-left {
  padding: 80px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: #f0ece6;
}

.p2-eyebrow {
  font-size: 8px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 28px;
  font-family: 'Didact Gothic',sans-serif;
}

.p2-title {
  font-family: 'Italiana',serif;
  font-size: clamp(44px,6vw,80px);
  font-weight: 400;
  line-height: 1.0;
  color: var(--noir);
  letter-spacing: -0.02em;
  margin-bottom: 28px;
}

.p2-body {
  font-size: 15px;
  line-height: 1.85;
  font-weight: 300;
  font-style: italic;
  color: rgba(8,8,8,0.5);
  max-width: 400px;
  margin-bottom: 48px;
}

.craft-list {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.craft-row {
  display: flex;
  gap: 20px;
  padding: 18px 0;
  border-bottom: 1px solid rgba(8,8,8,0.08);
  align-items: baseline;
}

.craft-n {
  font-size: 9px;
  letter-spacing: 0.15em;
  color: var(--accent);
  font-family: 'Didact Gothic',sans-serif;
  width: 24px;
  flex-shrink: 0;
}

.craft-t {
  font-size: 14px;
  font-style: italic;
  color: rgba(8,8,8,0.6);
}

.p2-right {
  padding: 80px;
  background: var(--white);
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-left: 1px solid rgba(8,8,8,0.06);
}

.maison-since {
  font-size: 9px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: rgba(8,8,8,0.25);
  margin-bottom: 40px;
  font-family: 'Didact Gothic',sans-serif;
}

.p2-numbers {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.num-item {
  display: flex;
  align-items: baseline;
  gap: 20px;
  padding-bottom: 28px;
  border-bottom: 1px solid rgba(8,8,8,0.06);
}

.num-big {
  font-family: 'Italiana',serif;
  font-size: 56px;
  color: var(--noir);
  line-height: 1;
}

.num-label {
  font-size: 12px;
  font-style: italic;
  color: rgba(8,8,8,0.45);
  line-height: 1.4;
}
/* PAGE 3 — CONTACT */

#p3 {
  background: var(--noir);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 80px;
  position: relative;
  overflow: hidden;
}

.p3-bg-text {
  position: absolute;
  font-family: 'Italiana',serif;
  font-size: 30vw;
  color: rgba(248,244,240,0.025);
  line-height: 1;
  letter-spacing: -0.06em;
  pointer-events: none;
  user-select: none;
}

.p3-content {
  position: relative;
  max-width: 560px;
}

.p3-mark {
  font-family: 'Italiana',serif;
  font-size: 9px;
  letter-spacing: 0.5em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 48px;
  display: block;
}

.p3-title {
  font-family: 'Italiana',serif;
  font-size: clamp(44px,8vw,100px);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--white);
  margin-bottom: 16px;
}

.p3-sub {
  font-size: 14px;
  font-style: italic;
  color: var(--dim);
  margin-bottom: 48px;
  line-height: 1.7;
}

.p3-contact-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
  border-top: 1px solid var(--mid);
  padding-top: 36px;
}

.p3-contact-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid var(--mid);
}

.p3-contact-key {
  font-size: 8px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: rgba(248,244,240,0.25);
  font-family: 'Didact Gothic',sans-serif;
}

.p3-contact-val {
  font-size: 13px;
  font-style: italic;
  color: rgba(248,244,240,0.65);
}
/* Curtain nav */

.c-nav {
  position: fixed;
  bottom: 40px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 800;
  display: flex;
  align-items: center;
  gap: 24px;
  background: rgba(8,8,8,0.7);
  border: 1px solid var(--mid);
  padding: 16px 32px;
  backdrop-filter: blur(20px);
}

.c-label {
  font-size: 8px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--dim);
  font-family: 'Didact Gothic',sans-serif;
  min-width: 80px;
  text-align: center;
}

.c-btn {
  width: 36px;
  height: 36px;
  border: 1px solid var(--mid);
  background: none;
  color: var(--dim);
  font-size: 16px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color .2s,color .2s;
  font-family: serif;
}

.c-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.c-dots {
  display: flex;
  gap: 8px;
}

.c-dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: rgba(248,244,240,0.2);
  border: none;
  cursor: pointer;
  transition: background .25s,transform .3s;
}

.c-dot.active {
  background: var(--accent);
  transform: scale(1.8);
}

@media (max-width: 768px) {
  #p0 .p0-layout {
    grid-template-columns: 1fr;
  }

  .p0-right {
    display: none;
  }

  .p0-left {
    padding: 40px 28px;
  }

  #p1 {
    padding: 40px 24px;
  }

  .look-grid {
    grid-template-columns: repeat(2,1fr);
  }

  #p2 {
    grid-template-columns: 1fr;
  }

  .p2-right {
    display: none;
  }

  .p2-left {
    padding: 40px 28px;
  }

  #p3 {
    padding: 40px 28px;
  }
}
const cLeft=document.getElementById('cLeft');
const cRight=document.getElementById('cRight');
const pages=document.querySelectorAll('.page');
const cdots=document.querySelectorAll('.c-dot');
const cLabel=document.getElementById('cLabel');
const labels=['Maison','Collection','Atelier','Contact'];
let cur=0,busy=false;

const dur=900;

function curtainTransition(prev,next,done){
  cLeft.style.transition=`transform ${dur*0.4}ms cubic-bezier(0.76,0,0.24,1)`;
  cRight.style.transition=`transform ${dur*0.4}ms cubic-bezier(0.76,0,0.24,1)`;
  cLeft.classList.add('close');
  cRight.classList.add('close');

  setTimeout(()=>{
    pages[prev].classList.remove('active');
    pages[next].classList.add('active');

    cLeft.style.transition=`transform ${dur*0.55}ms cubic-bezier(0.25,1,0.5,1)`;
    cRight.style.transition=`transform ${dur*0.55}ms cubic-bezier(0.25,1,0.5,1)`;
    cLeft.classList.remove('close');
    cRight.classList.remove('close');

    setTimeout(()=>{ done&&done(); },dur*0.6);
  },dur*0.42);
}

function goTo(n){
  if(busy||n===cur)return;
  busy=true;
  const prev=cur;cur=n;
  cdots.forEach((d,i)=>d.classList.toggle('active',i===cur));
  cLabel.textContent=labels[cur];
  curtainTransition(prev,cur,()=>{busy=false;});
}

document.getElementById('cNext').onclick=()=>goTo(Math.min(3,cur+1));
document.getElementById('cPrev').onclick=()=>goTo(Math.max(0,cur-1));
cdots.forEach(d=>d.addEventListener('click',()=>goTo(+d.dataset.i)));
document.querySelectorAll('[data-next]').forEach(b=>b.addEventListener('click',()=>goTo(+b.dataset.next)));

let wt=0;
window.addEventListener('wheel',e=>{
  const now=Date.now();if(now-wt<1100)return;wt=now;
  goTo(Math.max(0,Math.min(3,cur+(e.deltaY>0?1:-1))));
},{passive:true});
document.addEventListener('keydown',e=>{
  if(e.key==='ArrowRight')goTo(Math.min(3,cur+1));
  if(e.key==='ArrowLeft')goTo(Math.max(0,cur-1));
});
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Page Transition 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: Vertical Split Curtain
Source: https://codefronts.com/motion/css-page-transitions/vertical-split-curtain/

Two full-height panels slide closed like theatre curtains, swap the page, then split apart with a different easing — a gold-seamed theatrical reveal. A Parisian haute couture house.
## HTML
```html
<!-- Curtain panels -->
<div class="curtain-left" id="cLeft"></div>
<div class="curtain-right" id="cRight"></div>

<div class="pages">

  <div class="page active" id="p0">
    <div class="p0-layout">
      <div class="p0-left">
        <div class="p0-mark">Maison Lécluse · Paris</div>
        <div class="p0-main">
          <div class="p0-season">Automne–Hiver 2025</div>
          <h1 class="p0-title">Entre<br>Ombre<br>&amp; Lumière</h1>
          <div class="p0-title-fr">Between shadow and light</div>
          <p class="p0-body">A collection born from the silences between words. Forty-two looks. Each one a conversation the body has alone.</p>
          <button class="p0-cta" data-next="1">Discover the collection <span class="p0-cta-arrow"></span></button>
        </div>
      </div>
      <div class="p0-right">
        <div class="silhouette-area">
          <div class="figure">
            <div class="fig-head"></div>
            <div class="fig-arm fig-arm-l"></div>
            <div class="fig-arm fig-arm-r"></div>
            <div class="fig-body"></div>
          </div>
        </div>
        <div class="p0-right-bottom">
          <div class="p0-detail-row"><div class="det-key">Maison</div><div class="det-val">Since 1967</div></div>
          <div class="p0-detail-row"><div class="det-key">Ateliers</div><div class="det-val">Paris · Florence</div></div>
          <div class="p0-detail-row"><div class="det-key">Collection</div><div class="det-val">AH 2025 · 42 looks</div></div>
          <div class="p0-detail-row"><div class="det-key">Runway</div><div class="det-val">Palais Royal, 4 Oct</div></div>
        </div>
      </div>
    </div>
  </div>

  <div class="page" id="p1">
    <div class="p1-top">
      <h2 class="p1-title">The<br>Collection</h2>
      <div class="p1-count">42 Looks · AH 2025</div>
    </div>
    <div class="look-grid">
      <div class="look"><div class="look-img"><div class="garment g1"></div></div><div class="look-num">Look 01</div><div class="look-name">L'aube noire</div></div>
      <div class="look"><div class="look-img"><div class="garment g2"></div></div><div class="look-num">Look 07</div><div class="look-name">Le voile froid</div></div>
      <div class="look"><div class="look-img"><div class="garment g3"></div></div><div class="look-num">Look 14</div><div class="look-name">La colonne</div></div>
      <div class="look"><div class="look-img"><div class="garment g4"></div></div><div class="look-num">Look 21</div><div class="look-name">Le bruissement</div></div>
      <div class="look"><div class="look-img"><div class="garment g5"></div></div><div class="look-num">Look 38</div><div class="look-name">La chute</div></div>
    </div>
  </div>

  <div class="page" id="p2">
    <div class="p2-left">
      <div class="p2-eyebrow">L'Atelier Lécluse</div>
      <h2 class="p2-title">Made by<br>hand, in<br>silence</h2>
      <p class="p2-body">Each garment passes through twenty-four pairs of hands before it leaves the atelier. We consider this not a process, but a conversation with the material.</p>
      <div class="craft-list">
        <div class="craft-row"><div class="craft-n">I</div><div class="craft-t">Pattern cutting by master tailleur</div></div>
        <div class="craft-row"><div class="craft-n">II</div><div class="craft-t">Hand-draping on the mannequin</div></div>
        <div class="craft-row"><div class="craft-n">III</div><div class="craft-t">Three fittings per garment minimum</div></div>
        <div class="craft-row"><div class="craft-n">IV</div><div class="craft-t">Handstitched finishing throughout</div></div>
        <div class="craft-row"><div class="craft-n">V</div><div class="craft-t">Final inspection by the directrice</div></div>
      </div>
    </div>
    <div class="p2-right">
      <div class="maison-since">Maison Lécluse · Since 1967</div>
      <div class="p2-numbers">
        <div class="num-item"><div class="num-big">58</div><div class="num-label">Years of haute<br>couture</div></div>
        <div class="num-item"><div class="num-big">24</div><div class="num-label">Artisan hands per<br>garment</div></div>
        <div class="num-item"><div class="num-big">200+</div><div class="num-label">Hours in a single<br>couture piece</div></div>
      </div>
    </div>
  </div>

  <div class="page" id="p3">
    <div class="p3-bg-text">ML</div>
    <div class="p3-content">
      <span class="p3-mark">Maison Lécluse · Paris</span>
      <h2 class="p3-title">Private<br>Fitting</h2>
      <p class="p3-sub">By appointment only. Ateliers are open to clients for consultation from Tuesday through Saturday.</p>
      <div class="p3-contact-grid">
        <div class="p3-contact-row"><div class="p3-contact-key">Address</div><div class="p3-contact-val">24 Rue du Faubourg Saint-Honoré</div></div>
        <div class="p3-contact-row"><div class="p3-contact-key">Telephone</div><div class="p3-contact-val">+33 1 42 68 00 00</div></div>
        <div class="p3-contact-row"><div class="p3-contact-key">Fitting hours</div><div class="p3-contact-val">Mar–Sam · 10h–18h</div></div>
        <div class="p3-contact-row"><div class="p3-contact-key">Correspondence</div><div class="p3-contact-val">atelier@lecluse.paris</div></div>
      </div>
    </div>
  </div>

</div>

<!-- Nav -->
<div class="c-nav">
  <button class="c-btn" id="cPrev">‹</button>
  <div class="c-dots">
    <button class="c-dot active" data-i="0"></button>
    <button class="c-dot" data-i="1"></button>
    <button class="c-dot" data-i="2"></button>
    <button class="c-dot" data-i="3"></button>
  </div>
  <div class="c-label" id="cLabel">Maison</div>
  <button class="c-btn" id="cNext">›</button>
</div>
```
## CSS
```css
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  --noir: #080808;
  --white: #f8f4f0;
  --warm: #e8e0d4;
  --dim: rgba(248,244,240,0.4);
  --accent: #c8a060;
  --mid: rgba(248,244,240,0.1);
  --dur: 900ms;
  --ease: cubic-bezier(0.76,0,0.24,1);
}

html,
body {
  height: 100%;
  overflow: hidden;
  background: var(--noir);
  font-family: 'Cormorant Garamond',serif;
}
/* Pages */

.pages {
  position: fixed;
  inset: 0;
}

.page {
  position: absolute;
  inset: 0;
  pointer-events: none;
  visibility: hidden;
}

.page.active {
  visibility: visible;
  pointer-events: auto;
}
/* Curtain panels */

.curtain-left,
.curtain-right {
  position: fixed;
  top: 0;
  bottom: 0;
  z-index: 700;
  background: var(--noir);
  will-change: transform;
}

.curtain-left {
  left: 0;
  width: 50%;
  transform: translateX(-100%);
  transform-origin: left;
}

.curtain-right {
  right: 0;
  width: 50%;
  transform: translateX(100%);
  transform-origin: right;
}
/* Centre seam line */

.curtain-left::after {
  content: '';
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: linear-gradient(180deg,transparent,var(--accent),transparent);
  opacity: 0;
}
/* States */

.curtain-left.close {
  transform: translateX(0);
}

.curtain-right.close {
  transform: translateX(0);
}

.curtain-left.close::after {
  opacity: 0.4;
}
/* PAGE 0 — MAISON */

#p0 {
  background: var(--noir);
  color: var(--white);
}

.p0-layout {
  height: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.p0-left {
  padding: 60px 80px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  border-right: 1px solid var(--mid);
}

.p0-mark {
  font-family: 'Italiana',serif;
  font-size: 11px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--dim);
}

.p0-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-bottom: 20px;
}

.p0-season {
  font-size: 8px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 24px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.p0-season::before {
  content: '';
  width: 20px;
  height: 1px;
  background: var(--accent);
}

.p0-title {
  font-family: 'Italiana',serif;
  font-size: clamp(52px,8vw,112px);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--white);
  margin-bottom: 24px;
}

.p0-title-fr {
  font-size: clamp(24px,3.5vw,48px);
  font-style: italic;
  font-weight: 300;
  color: rgba(248,244,240,0.35);
  margin-bottom: 40px;
}

.p0-body {
  font-size: 13px;
  line-height: 1.9;
  font-weight: 300;
  color: var(--dim);
  max-width: 380px;
  font-style: italic;
}

.p0-cta {
  margin-top: 40px;
  display: inline-flex;
  align-items: center;
  gap: 16px;
  font-size: 9px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--white);
  cursor: pointer;
  background: none;
  border: none;
  font-family: 'Didact Gothic',sans-serif;
  transition: color .2s;
}

.p0-cta:hover {
  color: var(--accent);
}

.p0-cta-arrow {
  width: 40px;
  height: 1px;
  background: currentColor;
  transition: width .3s;
  position: relative;
}

.p0-cta-arrow::after {
  content: '';
  position: absolute;
  right: -1px;
  top: -3px;
  width: 7px;
  height: 7px;
  border-right: 1px solid currentColor;
  border-top: 1px solid currentColor;
  transform: rotate(45deg);
}

.p0-cta:hover .p0-cta-arrow {
  width: 64px;
}

.p0-right {
  display: grid;
  grid-template-rows: 1fr 1fr;
  padding: 60px;
  gap: 0;
}
/* Abstract fashion illustration using CSS shapes */

.silhouette-area {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.figure {
  position: relative;
  width: 80px;
  height: 200px;
}

.fig-body {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 48px;
  height: 140px;
  background: linear-gradient(180deg,rgba(200,160,96,0.2),rgba(200,160,96,0.06));
  border: 1px solid rgba(200,160,96,0.2);
  border-radius: 2px 2px 0 0;
}

.fig-head {
  position: absolute;
  bottom: 136px;
  left: 50%;
  transform: translateX(-50%);
  width: 20px;
  height: 24px;
  border-radius: 50%;
  background: rgba(200,160,96,0.15);
  border: 1px solid rgba(200,160,96,0.2);
}

.fig-arm {
  position: absolute;
  height: 1px;
  background: rgba(200,160,96,0.25);
  top: 72px;
}

.fig-arm-l {
  width: 32px;
  right: 48px;
}

.fig-arm-r {
  width: 32px;
  left: 48px;
}

.p0-right-bottom {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 16px;
}

.p0-detail-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  border-bottom: 1px solid var(--mid);
  padding: 12px 0;
}

.det-key {
  font-size: 8px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: rgba(248,244,240,0.25);
  font-family: 'Didact Gothic',sans-serif;
}

.det-val {
  font-size: 12px;
  font-style: italic;
  color: rgba(248,244,240,0.6);
}
/* PAGE 1 — COLLECTION */

#p1 {
  background: #0c0c0c;
  color: var(--white);
  padding: 60px 80px;
  display: flex;
  flex-direction: column;
}

.p1-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 52px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--mid);
}

.p1-title {
  font-family: 'Italiana',serif;
  font-size: clamp(44px,7vw,100px);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: -0.02em;
}

.p1-count {
  font-size: 9px;
  letter-spacing: 0.25em;
  color: var(--dim);
  font-family: 'Didact Gothic',sans-serif;
  text-transform: uppercase;
}

.look-grid {
  display: grid;
  grid-template-columns: repeat(5,1fr);
  gap: 12px;
  flex: 1;
}

.look {
  display: flex;
  flex-direction: column;
  gap: 12px;
  cursor: pointer;
}

.look-img {
  flex: 1;
  border: 1px solid rgba(248,244,240,0.06);
  position: relative;
  overflow: hidden;
  min-height: 200px;
  background: linear-gradient(180deg,#111,#0a0a0a);
  transition: border-color .3s;
}

.look:hover .look-img {
  border-color: rgba(200,160,96,0.3);
}
/* Abstract garment shape */

.garment {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 60%;
  background: rgba(200,160,96,0.08);
  border-top: 1px solid rgba(200,160,96,0.15);
}

.g1 {
  height: 70%;
  border-radius: 2px 2px 0 0;
}

.g2 {
  height: 85%;
  clip-path: polygon(20% 0,80% 0,100% 100%,0 100%);
}

.g3 {
  height: 60%;
  border-radius: 40% 40% 0 0;
}

.g4 {
  height: 75%;
  clip-path: polygon(0 0,100% 0,90% 100%,10% 100%);
}

.g5 {
  height: 90%;
  clip-path: polygon(30% 0,70% 0,100% 100%,0 100%);
}

.look-num {
  font-size: 8px;
  letter-spacing: 0.2em;
  color: var(--accent);
  font-family: 'Didact Gothic',sans-serif;
}

.look-name {
  font-family: 'Cormorant Garamond',serif;
  font-size: 13px;
  font-style: italic;
  color: rgba(248,244,240,0.7);
}
/* PAGE 2 — ATELIER */

#p2 {
  background: var(--white);
  color: var(--noir);
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.p2-left {
  padding: 80px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: #f0ece6;
}

.p2-eyebrow {
  font-size: 8px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 28px;
  font-family: 'Didact Gothic',sans-serif;
}

.p2-title {
  font-family: 'Italiana',serif;
  font-size: clamp(44px,6vw,80px);
  font-weight: 400;
  line-height: 1.0;
  color: var(--noir);
  letter-spacing: -0.02em;
  margin-bottom: 28px;
}

.p2-body {
  font-size: 15px;
  line-height: 1.85;
  font-weight: 300;
  font-style: italic;
  color: rgba(8,8,8,0.5);
  max-width: 400px;
  margin-bottom: 48px;
}

.craft-list {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.craft-row {
  display: flex;
  gap: 20px;
  padding: 18px 0;
  border-bottom: 1px solid rgba(8,8,8,0.08);
  align-items: baseline;
}

.craft-n {
  font-size: 9px;
  letter-spacing: 0.15em;
  color: var(--accent);
  font-family: 'Didact Gothic',sans-serif;
  width: 24px;
  flex-shrink: 0;
}

.craft-t {
  font-size: 14px;
  font-style: italic;
  color: rgba(8,8,8,0.6);
}

.p2-right {
  padding: 80px;
  background: var(--white);
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-left: 1px solid rgba(8,8,8,0.06);
}

.maison-since {
  font-size: 9px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: rgba(8,8,8,0.25);
  margin-bottom: 40px;
  font-family: 'Didact Gothic',sans-serif;
}

.p2-numbers {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.num-item {
  display: flex;
  align-items: baseline;
  gap: 20px;
  padding-bottom: 28px;
  border-bottom: 1px solid rgba(8,8,8,0.06);
}

.num-big {
  font-family: 'Italiana',serif;
  font-size: 56px;
  color: var(--noir);
  line-height: 1;
}

.num-label {
  font-size: 12px;
  font-style: italic;
  color: rgba(8,8,8,0.45);
  line-height: 1.4;
}
/* PAGE 3 — CONTACT */

#p3 {
  background: var(--noir);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 80px;
  position: relative;
  overflow: hidden;
}

.p3-bg-text {
  position: absolute;
  font-family: 'Italiana',serif;
  font-size: 30vw;
  color: rgba(248,244,240,0.025);
  line-height: 1;
  letter-spacing: -0.06em;
  pointer-events: none;
  user-select: none;
}

.p3-content {
  position: relative;
  max-width: 560px;
}

.p3-mark {
  font-family: 'Italiana',serif;
  font-size: 9px;
  letter-spacing: 0.5em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 48px;
  display: block;
}

.p3-title {
  font-family: 'Italiana',serif;
  font-size: clamp(44px,8vw,100px);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--white);
  margin-bottom: 16px;
}

.p3-sub {
  font-size: 14px;
  font-style: italic;
  color: var(--dim);
  margin-bottom: 48px;
  line-height: 1.7;
}

.p3-contact-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
  border-top: 1px solid var(--mid);
  padding-top: 36px;
}

.p3-contact-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid var(--mid);
}

.p3-contact-key {
  font-size: 8px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: rgba(248,244,240,0.25);
  font-family: 'Didact Gothic',sans-serif;
}

.p3-contact-val {
  font-size: 13px;
  font-style: italic;
  color: rgba(248,244,240,0.65);
}
/* Curtain nav */

.c-nav {
  position: fixed;
  bottom: 40px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 800;
  display: flex;
  align-items: center;
  gap: 24px;
  background: rgba(8,8,8,0.7);
  border: 1px solid var(--mid);
  padding: 16px 32px;
  backdrop-filter: blur(20px);
}

.c-label {
  font-size: 8px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--dim);
  font-family: 'Didact Gothic',sans-serif;
  min-width: 80px;
  text-align: center;
}

.c-btn {
  width: 36px;
  height: 36px;
  border: 1px solid var(--mid);
  background: none;
  color: var(--dim);
  font-size: 16px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color .2s,color .2s;
  font-family: serif;
}

.c-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.c-dots {
  display: flex;
  gap: 8px;
}

.c-dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: rgba(248,244,240,0.2);
  border: none;
  cursor: pointer;
  transition: background .25s,transform .3s;
}

.c-dot.active {
  background: var(--accent);
  transform: scale(1.8);
}

@media (max-width: 768px) {
  #p0 .p0-layout {
    grid-template-columns: 1fr;
  }

  .p0-right {
    display: none;
  }

  .p0-left {
    padding: 40px 28px;
  }

  #p1 {
    padding: 40px 24px;
  }

  .look-grid {
    grid-template-columns: repeat(2,1fr);
  }

  #p2 {
    grid-template-columns: 1fr;
  }

  .p2-right {
    display: none;
  }

  .p2-left {
    padding: 40px 28px;
  }

  #p3 {
    padding: 40px 28px;
  }
}
```

## JavaScript
```js
const cLeft=document.getElementById('cLeft');
const cRight=document.getElementById('cRight');
const pages=document.querySelectorAll('.page');
const cdots=document.querySelectorAll('.c-dot');
const cLabel=document.getElementById('cLabel');
const labels=['Maison','Collection','Atelier','Contact'];
let cur=0,busy=false;

const dur=900;

function curtainTransition(prev,next,done){
  cLeft.style.transition=`transform ${dur*0.4}ms cubic-bezier(0.76,0,0.24,1)`;
  cRight.style.transition=`transform ${dur*0.4}ms cubic-bezier(0.76,0,0.24,1)`;
  cLeft.classList.add('close');
  cRight.classList.add('close');

  setTimeout(()=>{
    pages[prev].classList.remove('active');
    pages[next].classList.add('active');

    cLeft.style.transition=`transform ${dur*0.55}ms cubic-bezier(0.25,1,0.5,1)`;
    cRight.style.transition=`transform ${dur*0.55}ms cubic-bezier(0.25,1,0.5,1)`;
    cLeft.classList.remove('close');
    cRight.classList.remove('close');

    setTimeout(()=>{ done&&done(); },dur*0.6);
  },dur*0.42);
}

function goTo(n){
  if(busy||n===cur)return;
  busy=true;
  const prev=cur;cur=n;
  cdots.forEach((d,i)=>d.classList.toggle('active',i===cur));
  cLabel.textContent=labels[cur];
  curtainTransition(prev,cur,()=>{busy=false;});
}

document.getElementById('cNext').onclick=()=>goTo(Math.min(3,cur+1));
document.getElementById('cPrev').onclick=()=>goTo(Math.max(0,cur-1));
cdots.forEach(d=>d.addEventListener('click',()=>goTo(+d.dataset.i)));
document.querySelectorAll('[data-next]').forEach(b=>b.addEventListener('click',()=>goTo(+b.dataset.next)));

let wt=0;
window.addEventListener('wheel',e=>{
  const now=Date.now();if(now-wt<1100)return;wt=now;
  goTo(Math.max(0,Math.min(3,cur+(e.deltaY>0?1:-1))));
},{passive:true});
document.addEventListener('keydown',e=>{
  if(e.key==='ArrowRight')goTo(Math.min(3,cur+1));
  if(e.key==='ArrowLeft')goTo(Math.max(0,cur-1));
});
```

Techniques used in this demo

Search CodeFronts

Loading…