[250221] TIL
오늘 한 일
리플로우와 리페인트를 줄일 수 있는 방법 정리
리플로우란 ?
- 웹 브라우저가 웹 페이지의 레이아웃을 계산하고, 요소의 위치와 크기를 다시 배치하는 과정
리플로우, 언제 발생하나요?
- DOM 요소 추가/제거
- 요소의 크기 변경 (너비, 높이, 패딩, 마진 등 변경될 때)
- 윈도우 크기 변경
- 폰트 변경
- CSS 속성 변경
리페인트란?
- 웹 브라우저가 시각적 요소를 다시 그리는 과정
리페인트, 언제 발생하나요?
- 색상 변경 (배경색, 테두리 등)
- 가시성 변경 (visibility, z-index)
- 배경 이미지 변경
- 텍스트 스타일 변경 (색상이나 그림자)
리플로우, 리페인트는 웹 페이지의 성능에 큰 영향을 미칠 수 있기 때문에, 최소화 하는 것이 중요 !
(특히 리플로우가 리페인트보다 영향을 많이줌)
리플로우 최소화 방법
1. DOM 조작 최소화
Batch DOM Changes
- 여러 DOM 변경을 한 번에 수행
- 변경 사항을 모아서 한 번에 적용하는 방법
Document Fragment 사용
- 여러 요소를 추가할 때
Document Fragment
를 사용하여 DOM에 한 번에 추가 - JS 에서 DOM 최적화하기 위해 사용되는 가벼운 DOM 객체
- 메모리에만 존재하고 실제 DOM 트리에는 포함되지 않는 특수한 노드
- 최종적으로 DOM에 추가할 때 한 번의 조작으로 처리할 수 있도록 도와줌
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const newElement = document.createElement('div');
fragment.appendChild(newElement);
}
document.body.appendChild(fragment);
2. 스타일 변경 최소화
- CSS 클래스 사용
- 개별 스타일 속성을 하나하나 변경하기보다는 CSS 클래스를 추가하거나 제거하기
// 나쁜 예시
document.getElementById('toggleButton').addEventListener('click', function() {
const element = document.getElementById('myElement');
if (element.style.width === '200px') {
element.style.width = '100px';
} else {
element.style.width= '200px';
}
});
// 좋은 예시
.highlight {
width : 200px
}
document.getElementById('toggleButton').addEventListener('click', function() {
const element = document.getElementById('myElement');
element.classList.toggle('highlight');
});
3. 오프라인에서 작업
- DOM 을 변경하기 전에, 요소를 문서에서 제거하고 변경 후 다시 추가
- 큰 DOM 트리에서 유용
document.getElementById('updateButton').addEventListener('click', function() {
const container = document.getElementById('container');
const element = document.getElementById('myElement');
// 요소를 문서에서 제거
container.removeChild(element);
// 요소 변경 (메모리에서만 이루어짐)
element.textContent = 'Updated Text';
element.style.color = 'red';
element.style.fontSize = '20px';
// 변경된 요소를 다시 추가
container.appendChild(element);
});
4. 레이아웃 읽기와 쓰기 분리
// 나쁜 예시
// offsetHeight를 읽은 후 높이를 변경하면
// offsetHeight를 읽기전에 브라우저는 레이아웃을 다시 계산해야 한다고 함
element.style.height = (element.offsetHeight + 10) + 'px';
// 좋은 예시
const height = element.offsetHeight; // 읽기
element.style.height = (height + 10) + 'px'; // 쓰기
5. CSS 속성 사용
transform
과opacity
속성을 사용하여 애니메이션 수행- 두 속성은 레이아웃이랑 페인팅 단계를 건너뛰고 합성 단계에서 처리되기 때문에 리플레이 리플로우를 유발하지 않음
- 참고
- DOM 생성 → 스타일 계산 → 레이아웃 → 페인팅 → 합성 (최종 그려질 요소를 합성)
리페인트 최소화 방법
1. 스타일 변경 최소화
- 여러 스타일 변경을 한 번에 수행
- 위에서 말한 것처럼 style 속성 여러 번 변경하는 대신, CSS 클래스를 사용하여 스타일 변경
2. 가시성 변경 최적화
visibility
대신display: none
을 사용하여 리페인트를 피할 수 있음- display none은 DOM에서 아예 제거하기 때문에 리페인트가 발생하지 않음
- 리플로우는 발생함
3. 애니메이션 최적화
transform
과opacity
속성을 사용하여 애니메이션 수행- 위와 마찬가지로 합성 단계에서 처리되기 때문에 리플레이, 리플로우 유발 X
4. 복잡한 CSS 선택자 피하기
- 복잡한 CSS 선택자는 브라우저가 스타일을 적용하는데 더 많은 시간을 소모하게 만듬
- 가능한 간단한 선택자 사용
5. CSS 속성 사용
will-change
속성 사용하여 브라우저에 어떤 속성이 변경될 것인지 미리 알려주어 최적화를 도움- 단, 남용하지 말아야함 오히려 성능에 부정적인 영향을 미칠 수 있음
.animated-box {
width: 100px;
height: 100px;
background-color: lightblue;
transition: transform 0.3s ease, opacity 0.3s ease;
will-change: background-color;
}
Leave a comment