"매 byte → 매 pixel 의 pipeline". 매 DOM + CSSOM → 매 Render Tree → 매 Layout → 매 Paint → 매 Composite. 매 web performance 의 fundamental. 매 each step 의 understand → 매 optimize 의 right tool.
매 핵심 step
1. DOM (Document Object Model)
매 HTML 의 incremental parse.
매 byte → token → node → tree.
매 partial 도 OK.
2. CSSOM (CSS Object Model)
매 CSS 의 parse.
매 render-blocking (vs DOM 의 incremental).
매 FOUC 방지.
3. Render Tree
매 DOM + CSSOM 의 결합.
매 visible element 만 (display:none 의 X).
4. Layout (Reflow)
매 geometry 계산 (position, size).
매 expensive — 매 entire subtree 의 trigger.
5. Paint (Repaint)
매 pixel 의 color / shadow.
매 layer per layer.
6. Compositing
매 layer 의 GPU 의 combine.
매 transform / opacity 의 composite-only.
Render-blocking resources
CSS (default).
<script> (sync).
→ 매 inline / async / defer 로 매 mitigate.
매 optimization
CSS
Inline critical CSS: 매 above-fold.
media="print" for print CSS.
async for non-critical: deferred.
PurgeCSS / Tree-shake: unused 제거.
JavaScript
async: 매 download parallel + 매 execute when ready.
defer: 매 download parallel + 매 execute after DOM.
Module split: code splitting.
Inline critical: small.
Image
Lazy loading: loading="lazy".
Modern format: AVIF, WebP.
Priority hint: fetchpriority="high".
Responsive: srcset, sizes.
Font
font-display: swap (or optional).
Preload: <link rel="preload">.
Subset: 매 unused glyph drop.
Network
HTTP/2 push (deprecated, use 103 Early Hints).
HTTP/3: 매 quic.
CDN: 매 edge.
Preconnect: 매 third-party.
매 anti-pattern (avoid)
매 layout property animate (top, left, width, height).
매 sync DOM measurement after write (forced reflow).
매 document.write (legacy).
매 huge inline CSS / JS.
매 measurement
DevTools Performance tab.
Lighthouse CRP report.
web-vitals (LCP, FCP).
💻 패턴
Async / defer JS
<!-- 매 critical inline --><script>// 매 inline + small + critical
document.documentElement.classList.add('js-enabled');</script><!-- 매 third-party analytics: async --><scriptasyncsrc="/analytics.js"></script><!-- 매 main app JS: defer --><scriptdefersrc="/app.js"></script><!-- 매 ❌ Avoid sync (default) --><scriptsrc="/legacy.js"></script>
Critical CSS inline
<head><style>/* 매 above-fold critical */body{font-family:system-ui;}.hero{display:flex;height:60vh;}</style><!-- 매 rest async --><linkrel="preload"href="/main.css"as="style"onload="this.onload=null;this.rel='stylesheet'"><noscript><linkrel="stylesheet"href="/main.css"></noscript></head>
Preload + preconnect
<head><!-- 매 critical asset preload --><linkrel="preload"href="/hero.avif"as="image"fetchpriority="high"><linkrel="preload"href="/inter.woff2"as="font"type="font/woff2"crossorigin><!-- 매 third-party preconnect --><linkrel="preconnect"href="https://api.example.com"><linkrel="dns-prefetch"href="https://cdn.example.com"></head>
Avoid forced reflow
// 매 ❌ Bad — 매 reflow per iteration
for(constelofitems){el.style.width=el.offsetWidth+10+'px';// 매 read + write
}// 매 ✅ Good — 매 batch read, then batch write
constwidths=items.map(el=>el.offsetWidth);// 매 read all
items.forEach((el,i)=>{el.style.width=widths[i]+10+'px';// 매 write all
});
Use transform / opacity (composite only)
/* 매 ❌ reflow */.modal-bad{transition:top200ms,width200ms;}/* 매 ✅ composite only */.modal-good{transition:transform200ms,opacity200ms;}.modal-good.show{transform:translateY(0);opacity:1;}.modal-good.hide{transform:translateY(-20px);opacity:0;}
will-change hint (sparingly)
.about-to-animate{will-change:transform;}/* 매 매 animation 완료 시 의 remove */
Image priority + lazy
<!-- 매 LCP candidate (above-fold) --><imgsrc="/hero.avif"alt="Hero"width="1200"height="600"fetchpriority="high"><!-- 매 below-fold --><imgsrc="/below.avif"alt="Below"width="800"height="600"loading="lazy"decoding="async">
Resource hint priority
<!-- 매 preload (high priority) --><linkrel="preload"href="/critical.css"as="style"><!-- 매 prefetch (next page hint) --><linkrel="prefetch"href="/next-page.html"><!-- 매 modulepreload --><linkrel="modulepreload"href="/module.js">
Lighthouse CRP analysis
npx lighthouse https://example.com --only-categories=performance \
--output=json --output-path=./report.json
# 매 매 critical-request-chains 의 review
node -e "
const r = require('./report.json');
console.log(JSON.stringify(r.audits['critical-request-chains'], null, 2));
"
DevTools Performance trace
1. Open DevTools → Performance tab.
2. Click record + reload page.
3. Stop after page loaded.
4. Look at Main thread:
- Long tasks (>50ms).
- Layout thrashing (purple bars).
- Paint cost (green).
5. Identify blocking resources.
Server-Timing (server contribution)
// 매 Express middleware
app.use((req,res,next)=>{conststart=Date.now();res.on('finish',()=>{res.set('Server-Timing',`total;dur=${Date.now()-start}`);});next();});// 매 client 의 visible
performance.getEntriesByType('navigation')[0].serverTiming;