Splash Screen

스플래시 스크린

The brief, purely static screen with just a logo that appears while an app is launching — a snapshot the system draws, not a loading animation.

Also known as: Launch screen런치 스크린
···
html
<div class="stage"><div class="phone"><div class="notch"></div><div class="screen" id="screen">
<div class="homeUnder">
  <div class="topbar2">Home</div>
  <div class="grid2"><div class="card3"></div><div class="card3"></div><div class="card3"></div><div class="card3"></div></div>
</div>
<div class="splash" id="splash"><div class="logo" id="logo"></div></div></div><div class="home"></div></div></div>
css
.stage{position:absolute;inset:0;display:grid;place-items:center;overflow:hidden}
.phone{position:relative;height:90vmin;max-height:640px;aspect-ratio:9/19.5;background:#08080c;
  border-radius:20%/8.6%;box-shadow:0 0 0 2px rgba(255,255,255,.08) inset,0 12px 30px rgba(0,0,0,.35)}
.phone .notch{position:absolute;left:50%;top:0;transform:translateX(-50%);width:38%;height:5.6%;
  background:#08080c;border-radius:0 0 46% 46%;z-index:80}
.phone .screen{position:absolute;top:7.6%;left:3%;right:3%;bottom:3%;border-radius:11%/4.6%;overflow:hidden;
  background:var(--surface);color:var(--fg)}
.phone .home{position:absolute;left:50%;bottom:1.1%;transform:translateX(-50%);width:32%;height:3px;
  border-radius:2px;background:rgba(255,255,255,.45);z-index:80}
.pfx{position:absolute;left:0;top:0;width:16px;height:16px;margin:-8px 0 0 -8px;border-radius:50%;
  background:color-mix(in srgb,var(--accent) 55%,transparent);
  box-shadow:0 0 0 6px color-mix(in srgb,var(--accent) 15%,transparent);pointer-events:none;z-index:999;
  transition:opacity .2s}
.pfx.hold{width:30px;height:30px;margin:-15px 0 0 -15px;
  box-shadow:0 0 0 9px color-mix(in srgb,var(--accent) 20%,transparent);
  transition:width .5s linear,height .5s linear,margin .5s linear,box-shadow .5s linear,opacity .2s}

.homeUnder{position:absolute;inset:0;background:var(--surface)}
.topbar2{padding:7% 8% 4%;font-weight:800;font-size:clamp(8px,3vmin,12px);border-bottom:1px solid var(--line)}
.grid2{padding:6% 8%;display:grid;grid-template-columns:1fr 1fr;gap:6%}
.card3{aspect-ratio:1;border-radius:10%;background:var(--line)}
.splash{position:absolute;inset:0;display:grid;place-items:center;background:var(--accent);z-index:5;transition:opacity .5s}
.splash.hide{opacity:0;pointer-events:none}
.logo{width:clamp(22px,15vmin,40px);height:clamp(22px,15vmin,40px);border-radius:26%;background:#fff;
  transform:scale(.5);opacity:0;transition:transform .45s cubic-bezier(.34,1.56,.64,1),opacity .3s}
.logo.show{transform:scale(1);opacity:1}
js
const pfx=document.createElement('div');pfx.className='pfx';document.body.appendChild(pfx);
const screenEl=document.getElementById('screen');
let pfxAuto=true;
function pfxHide(){pfx.style.opacity='0';}
addEventListener('pointerdown',()=>{pfxAuto=false;pfxHide();},{capture:true});
function pfxAt(fx,fy){
  const r=screenEl.getBoundingClientRect();
  const x=r.left+r.width*fx, y=r.top+r.height*fy;
  pfx.style.transform='translate('+x+'px,'+y+'px)';
  return {x,y};
}
function pfxWalk(x0,y0,x1,y1,ms){
  return new Promise(res=>{
    const start=performance.now();
    function step(now){
      if(!pfxAuto) return res();
      const p=Math.min(1,(now-start)/ms), e=1-Math.pow(1-p,3);
      pfxAt(x0+(x1-x0)*e, y0+(y1-y0)*e);
      if(p<1) requestAnimationFrame(step); else res();
    }
    requestAnimationFrame(step);
  });
}
function pfxWait(ms){
  return new Promise(res=>{
    const start=performance.now();
    function step(now){ if(!pfxAuto) return res(); if(now-start<ms) requestAnimationFrame(step); else res(); }
    requestAnimationFrame(step);
  });
}

const splash=document.getElementById('splash'), logo=document.getElementById('logo');
function skip(){ splash.classList.add('hide'); }
splash.addEventListener('pointerdown',()=>{ pfxAuto=false; pfxHide(); skip(); });
async function autoSeq(){
  while(pfxAuto){
    splash.classList.remove('hide'); logo.classList.remove('show'); void splash.offsetWidth;
    pfxAt(0.5,0.5);
    await pfxWait(200); if(!pfxAuto)break;
    logo.classList.add('show');
    await pfxWait(950); if(!pfxAuto)break;
    skip();
    await pfxWait(1300);
  }
}
autoSeq();

iOS manages the first frame through a `LaunchScreen` storyboard (or `UILaunchScreen` in Info.plist); Android has done it via the `SplashScreen` API since Android 12. Both share one constraint — this has to be a completely static snapshot, no network calls, no text that changes at runtime. It's closer to the word's original sense (a single splash) than to a progress indicator.

Because the system draws it before your own code runs, there's a hard limit on how much the logo can be animated — Android 12+ ships a built-in zoom-out transition for the icon, but anything beyond that has to be handled by app code once the real first screen takes over.

The most common mistake is treating it as a branding opportunity and adding a long fade-in or spin. That only slows down how fast the app feels to open — show it as briefly as possible and hand off to real content, or a skeleton, as fast as you can.

When to use

Use it only for a cold start — actually launching the app. Don't reuse it for screen transitions or data loading; a spinner or skeleton belongs there instead.