9148c358d0
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를 Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류. - 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로 자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거, 동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거. - 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming, Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business, Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로, 나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는 title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백). 원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지. - 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서. - 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는 지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지. - Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경. - 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
5.1 KiB
5.1 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-성능-최적화-reflow-repaint | 성능 최적화(Reflow & Repaint) | 10_Wiki/Topics | verified | self |
|
none | A | 0.93 | applied |
|
2026-05-10 | pending |
|
성능 최적화(Reflow & Repaint)
매 한 줄
"매 layout(=reflow) 의 비싸고, paint 의 cheap-er, composite 의 cheapest". 매 DOM/CSS write 의 invalidate 의 trigger — geometry change → reflow + repaint, color-only change → repaint, transform/opacity → composite-only. Layout thrashing 의 batch read/write 의 fix.
매 핵심
매 cost ladder
- Composite only (cheap, 60fps):
transform,opacity,filter(some). - Paint (medium):
color,background-color,box-shadow,border-radius. - Layout (Reflow) (expensive):
width,height,top/left,margin,padding,font-size,display. - Full reflow trigger:
<html>font change, viewport resize.
매 reflow triggers (write)
- DOM 의 add/remove.
display/positionchange.- size/box-model property change.
- font/text content change.
- pseudo-class (
:hover) 의 layout-affecting style.
매 forced sync layout (read)
offsetTop/Left/Width/Height,clientTop/...,scrollTop/....getComputedStyle(),getBoundingClientRect().- 매 pending invalidation 의 있을 때 read → 매 browser 의 immediate layout 의 trigger.
💻 패턴
Layout thrash 의 fix (read-then-write)
// X — N reflow (each iteration forces layout)
boxes.forEach(b => {
const w = b.offsetWidth;
b.style.width = (w + 10) + 'px';
});
// O — 1 reflow (read all, then write all)
const widths = boxes.map(b => b.offsetWidth);
boxes.forEach((b, i) => b.style.width = (widths[i] + 10) + 'px');
requestAnimationFrame batching
let pending = false;
function update(el) {
if (pending) return;
pending = true;
requestAnimationFrame(() => {
el.style.transform = `translateX(${nextX}px)`;
pending = false;
});
}
window.addEventListener('scroll', () => update(stickyEl));
Detach → mutate → reattach (huge DOM ops)
const list = document.getElementById('list');
const fragment = document.createDocumentFragment();
for (const item of items) {
const li = document.createElement('li');
li.textContent = item.name;
fragment.appendChild(li);
}
list.appendChild(fragment); // 1 reflow, not N
transform 의 substitute (animation)
/* X — top change → reflow per frame */
@keyframes slide-bad { from { top: 0 } to { top: 100px } }
/* O — transform → composite only */
@keyframes slide-good { from { transform: translateY(0) } to { transform: translateY(100px) } }
will-change (sparingly)
/* 매 animation 직전 의 hint, 매 finish 후 remove */
.card { will-change: transform; }
.card.done { will-change: auto; }
contain (CSS containment)
/* 매 subtree 의 layout/paint 의 isolate — outer 의 invalidation 의 not propagate */
.widget { contain: layout paint; }
Position fixed/sticky (composite layer)
.toolbar {
position: sticky; top: 0;
/* GPU layer — scroll 시 reflow 없음 */
}
IntersectionObserver (no scroll handler)
const io = new IntersectionObserver((entries) => {
for (const e of entries) {
if (e.isIntersecting) e.target.classList.add('in-view');
}
}, { rootMargin: '0px 0px -10% 0px' });
images.forEach(img => io.observe(img));
매 결정 기준
| 변경 | Cost |
|---|---|
transform / opacity |
composite only — 60fps OK |
background-color |
paint — usually OK |
top/left/width/height |
layout — animation 의 avoid |
display |
layout — modal toggle 의 OK, animation 의 X |
font-size (root) |
full document reflow — extreme cost |
기본값: 매 animation → transform/opacity 만, batch read/write, large insert → DocumentFragment, off-screen → content-visibility / IntersectionObserver.
🔗 Graph
🤖 LLM 활용
언제: layout thrash 의 detect (read-write interleave pattern), animation property 의 review. 언제 X: actual paint profiling — Chrome DevTools Performance/Layers panel 의 use.
❌ 안티패턴
will-changeeverywhere: 매 GPU memory exhaustion.top/leftanimation: 매 reflow per frame —transform의 substitute.- scroll handler 의 layout read: 매 thrash — IntersectionObserver 의 use.
innerHTML의 loop: 매 N reflow — fragment 의 build.
🧪 검증 / 중복
- Verified (web.dev/articles/animations-guide, Paul Lewis "Avoid Large, Complex Layouts", CSSOM View spec).
- 신뢰도 A.
🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — reflow trigger + 8 패턴 + 결정 기준 의 정리 |