"매 Reflow = geometry 재계산, Repaint = pixel 재그리기". Reflow 매 layout phase — DOM/CSS geometry 변화 시 발생 — 매 expensive. Repaint 매 paint phase — color/visibility 변화 — 매 cheaper. 매 60fps 의 핵심 = 매 둘 다 피하기 + 매 compositor-only 속성 사용.
offsetWidth, getBoundingClientRect() 읽기 — 매 force sync layout.
viewport resize.
매 Repaint-only trigger
color, background-color, visibility, outline.
매 Compositor-only (best)
transform, opacity, filter (with will-change).
매 main thread 의 X — 매 GPU layer 만.
매 60fps 의 핵심.
매 Layout Thrashing
읽기/쓰기 alternate — 매 매번 force reflow — 매 worst.
batch 매 read 다음 batch 매 write — 매 1회 reflow.
💻 패턴
Compositor-only animation
/* 매 GOOD — transform/opacity 만 — GPU */.box{transition:transform0.3s,opacity0.3s;will-change:transform;/* 매 hint — 매 layer 미리 promote */}.box:hover{transform:translateX(20px)scale(1.1);opacity:0.8;}/* 매 BAD — top/left — 매 reflow */.box-bad:hover{top:20px;left:20px;}
Read-write batching
// 매 BAD — thrashing
items.forEach(el=>{el.style.width=el.offsetWidth+10+'px';// read + write
});// 매 GOOD — batch
constwidths=items.map(el=>el.offsetWidth);// all reads
items.forEach((el,i)=>{el.style.width=widths[i]+10+'px';// all writes
});
DocumentFragment for bulk insert
constfrag=document.createDocumentFragment();for(leti=0;i<1000;i++){constli=document.createElement('li');li.textContent=`Item ${i}`;frag.appendChild(li);// 매 detached — 매 reflow 의 X
}document.querySelector('ul').appendChild(frag);// 매 1회 reflow
will-change (정확)
/* 매 hover 직전 추가, 끝 후 제거 */.card{will-change:auto;}.card:hover{will-change:transform;}/* 매 항상 will-change — 매 anti-pattern — 매 메모리 낭비 */
CSS Containment
.widget{contain:layoutpaint;/* 매 외부 영향 차단 — 매 reflow 매 widget 내부 만 */}