차근차근 개발중
[WEB] 리플로우(reflow)와 리페인트(repaint) 본문
렌더링 과정중에 성능최적화를 고민하기위해서는 리플로우와 리페인트단계를 빼놓을 수 없다
그렇기때문에 리플로우와 리페인트에 대해서 공부해보자
화면이 사용자에게 표출된 후에 노드가 추가되거나 요소의 스타일이 달라졌을때 발생하는게 리플로우(Reflow)와 리페인트(Repaint)입니다
📌 리플로우란(Reflow)?
- 요소의 위치나 크기가 변경되어 페이지의 레이아웃을 다시 계산하는 과정입니다. 변경하려는 특정요소의 위치와 크기뿐만 아니라 연관된 요소들의 위치와 크기도 재계산하기 때문에 성능 저하가 일어납니다.
• 발생원인
- DOM요소 추가/ 제거
- 요소의 크기, 위치 변경
- 폰트변경, 텍스트 내용변경
- 윈도우 크기조정
- css 스타일 변경 ex) margin, padding등
• 특징
- 계산 비용이 높다
- 하나의 요소가 리플로우가되면 그 자식 요소와 부모 요소도 영향을 받을 수 있다.
• 성능 최적화 팁
- 여러 DOM변경을 한 번에 처리합니다.
// 나쁜 예 - 리플로우 여러 번 발생
const element = document.getElementById('box');
element.style.width = '100px';
element.style.height = '100px';
element.style.margin = '10px';
// 좋은 예 - 리플로우 한 번만 발생
const element = document.getElementById('box');
element.style.cssText = 'width: 100px; height: 100px; margin: 10px;';
// 또는 클래스 사용
element.className = 'new-box';
- 여러 요소를 추가할 때 메모리에서 작업 후 한 번에 DOM에 삽입
// 나쁜 예 - 각 항목마다 리플로우 발생
const list = document.getElementById('list');
for (let i = 0; i < 100; i++) {
const item = document.createElement('li');
item.textContent = `항목 ${i}`;
list.appendChild(item); // 매번 리플로우 발생
}
// 좋은 예 - 리플로우 한 번만 발생
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const item = document.createElement('li');
item.textContent = `항목 ${i}`;
fragment.appendChild(item);
}
list.appendChild(fragment); // 리플로우 한 번만 발생
※ DocumentFragment는 메모리 상에만 존재하는 경량화된 DOM 조각입니다. 실제 DOM에 직접 연결되어 있지 않기 때문에, DocumentFragment에 변경 사항을 추가해도 라이브 DOM에 영향을 주지 않습니다.
- position: absolute/fixed 활용하기
/* 절대 위치를 사용하면 이 요소의 변경이 다른 요소에 영향을 미치지 않음 */
.overlay {
position: fixed;
top: 0;
left: 0;
/* 변경해도 다른 요소에 리플로우 영향 최소화 */
}
📌 리페인팅이란(Repainting)?
- 요소의 시각적인 스타일만 변경되어 화면을 다시그리는 과정입니다. 레이아웃에는 영향을 주지 않습니다.
• 발생원인
- 색상, 투명도, 그림자 효과 변경
- visibility 속성변경
• 특징
- 리플로우보다 비용이 적음
- 레이아웃에는 영향을 주지 않음
- 리플로우가 일어났을때 리페인팅은 항상 유발되지만 리페인팅은 항상 리플로우를 유발하지는 않습니다.
• 리페인팅(Repainting) 성능 최적화 팁
- 여러 스타일 변경을 한 번에 적용하기
// 나쁜 예 - 여러 번의 리페인팅 발생
const element = document.getElementById('box');
element.style.backgroundColor = 'red';
element.style.color = 'white';
element.style.boxShadow = '2px 2px 5px #999';
// 좋은 예 - 한 번의 리페인팅만 발생
element.style.cssText = 'background-color: red; color: white; box-shadow: 2px 2px 5px #999;';
// 또는 클래스 추가
element.classList.add('styled-box');
- 화면에 보이지 않는 요소나 중복 요소 제거하기
// 가상 스크롤링 구현 예시 - 화면에 보이는 요소만 렌더링
function renderVisibleItems(scrollPosition) {
const container = document.getElementById('container');
container.innerHTML = ''; // 기존 내용 지우기
const visibleItems = allItems.slice(
Math.floor(scrollPosition / itemHeight),
Math.ceil((scrollPosition + viewportHeight) / itemHeight)
);
visibleItems.forEach(item => {
const element = document.createElement('div');
element.textContent = item.text;
container.appendChild(element);
});
}
- JavaScript보다 CSS 트랜지션 활용하기
css
.button {
background-color: blue;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: darkblue;
}
javascript
// 나쁜 예 - JavaScript로 색상 변경
element.addEventListener('mouseover', function() {
element.style.backgroundColor = 'darkblue';
});
// 좋은 예 - CSS 클래스 토글로 처리 (브라우저 최적화 활용)
element.addEventListener('mouseover', function() {
element.classList.add('hover');
});
Comments