"매 page 의 reload 없이 매 URL + DOM 의 swap". Soft navigation 매 SPA pattern, History API (pushState) + view transitions 매 modern impl. 매 2025+ 의 Web Vitals 매 soft-nav LCP/INP 의 attribute (Soft Navigations API), 매 Chrome 138+ stable.
매 핵심
매 hard vs soft 의 line
Hard nav: 매 full document load, 매 unload/load, fresh JS context.
Soft nav: 매 client-side router. URL 매 history.pushState, DOM 매 partial swap. 매 same JS context.
CWV impact: 매 v1 vitals 매 hard 만 measure. 매 2025 Soft Navigations API 매 soft 도 LCP/INP/CLS 의 attribute.
매 detection criteria (Chrome)
User-initiated (click, keypress).
URL change via History API.
DOM change (significant) post-event.
매 셋 의 모두 conjunction → soft-nav event.
매 view transitions API
same-doc: document.startViewTransition(() => updateDOM()). 매 2024 stable.
cross-doc (MPA mode): 매 2025 Chrome 126+. @view-transition { navigation: auto }.
매 Web Animations API 의 wrap, 매 CSS ::view-transition-* 의 customize.
// app/products/[id]/page.tsx
import{Suspense}from'react';exportdefaultasyncfunctionProduct({params}){constdata=awaitfetch(`/api/p/${params.id}`).then(r=>r.json());return(<Suspensefallback={<Skeleton/>}><ProductViewdata={data}/></Suspense>);}// link triggers soft nav by default
importLinkfrom'next/link';<Linkhref="/products/42"prefetch>View</Link>
언제: 매 router code scaffolding, 매 RUM analytics dashboard query gen, 매 view-transition CSS draft.
언제 X: 매 perf measurement (real RUM data needed), 매 a11y validation (manual + axe).
❌ 안티패턴
No focus management: 매 soft nav 후 focus 매 lost. 매 a11y violation. route.focus() on <main>.
No scroll restoration: 매 back-button 매 wrong scroll. history.scrollRestoration='manual' + manual restore.
CLS spike: 매 layout shift 의 unmeasured. 매 view-transitions 의 use.
Blocking JS during nav: 매 INP 매 800ms+. 매 Suspense / streaming.
No prefetch budget: 매 hover 매 모든 link 의 fetch — 매 bandwidth waste.