Two-phase view transition preview

2단계 뷰 전환 미리보기

An intermediate state separates the outgoing and incoming parts of a view transition.

···
html
<div class="v two"><header>2-PHASE TRANSITION <span id="phase">exit</span></header><div class="stage two-stage"><div class="two-screen" id="screen"><span id="view">A</span><i id="loader"></i></div><div class="two-steps"><b id="s0">EXIT</b><b id="s1">WAIT</b><b id="s2">ENTER</b></div></div><input id="scrub" aria-label="Transition phase" type="range" min="0" max="2" value="0"><div class="muted">old view → middle → new view</div></div>
css
.v{width:min(94vw,760px);height:min(88vh,320px);padding:clamp(9px,2.4vmin,18px);border:1px solid var(--line);border-radius:12px;background:var(--surface);font:500 clamp(12px,2.4vmin,16px)/1.3 var(--font-sans,system-ui,sans-serif);display:flex;flex-direction:column;gap:clamp(5px,1.4vmin,10px);overflow:hidden}.v header{display:flex;align-items:center;justify-content:space-between;gap:8px;color:var(--accent);font-weight:700}.v header span{color:var(--muted);font-weight:500}.v .stage{flex:1;min-height:0;position:relative}.v .muted{color:var(--muted)}.v .active{background:color-mix(in srgb,var(--accent) 18%,var(--surface));border-color:var(--accent)!important;color:var(--fg)}.v button{font:inherit;color:var(--fg);background:var(--bg);border:1px solid var(--line);border-radius:7px;padding:5px 8px;cursor:pointer}.two-stage{display:flex;align-items:center;justify-content:center;gap:clamp(9px,3vmin,30px)}.two-screen{width:39%;height:85%;border:2px solid var(--accent);border-radius:10px;background:var(--bg);display:grid;place-items:center;position:relative;overflow:hidden}.two-screen span{font-size:clamp(34px,9vmin,60px);font-weight:800;transition:transform .15s,opacity .15s}.two-screen.exit span{transform:translateX(-70%);opacity:.35}.two-screen.wait span{opacity:0}.two-screen.enter span{transform:translateX(0);opacity:1}.two-screen i{position:absolute;width:30%;height:4px;border-radius:4px;background:var(--accent-2);opacity:0;animation:loading 1s ease-in-out infinite alternate}.two-screen.wait i{opacity:1}@keyframes loading{to{transform:scaleX(.35)}}.two-steps{display:flex;flex-direction:column;gap:7px}.two-steps b{font-size:clamp(12px,2.5vmin,14px);border:1px solid var(--line);border-radius:6px;padding:5px 8px;color:var(--muted)}.two-steps b.on{border-color:var(--accent);color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,var(--surface))}.two input{width:82%;align-self:center;accent-color:var(--accent);margin:0;height:16px}
js
const scrub=document.getElementById("scrub"),screen=document.getElementById("screen"),phase=document.getElementById("phase");const names=["exit","wait","enter"];function show(i){scrub.value=i;screen.className="two-screen "+names[i];document.getElementById("view").textContent=i===2?"B":"A";phase.textContent=names[i];names.forEach((_,j)=>document.getElementById("s"+j).classList.toggle("on",j===i))}let i=0;show(i);let timer=setInterval(()=>show(i=(i+1)%3),850);scrub.addEventListener("input",()=>{clearInterval(timer);show(Number(scrub.value))})

A two-phase view transition separates the exit of the old view from the entry of the new one. The intermediate state can coordinate asynchronous preparation with visual continuity.

Scrub the demo timeline to see exit, intermediate, and entry states. As of September 2026 this feature is still in testing, so production code needs support detection and an ordinary transition fallback.

When to use

Consider it when a transition needs an explicit intermediate state while data loads.

Open as page ↗