게시: 2015년 3월 20일, 최종 업데이트: 2025년 5월 7일
레이아웃은 브라우저가 요소의 기하학적 정보를 파악하는 곳입니다. 즉, 페이지에서의 크기와 위치입니다. 각 요소에는 사용된 CSS, 요소의 콘텐츠 또는 상위 요소를 기반으로 한 명시적 또는 암시적 크기 정보가 있습니다. 이 프로세스는 Chrome (및 Edge와 같은 파생된 브라우저) 및 Safari에서 레이아웃이라고 합니다. Firefox에서는 이를 리플로라고 부르지만 프로세스는 실제로 동일합니다.
스타일 계산과 마찬가지로 레이아웃 비용과 관련하여 즉시 고려해야 할 사항은 다음과 같습니다.
- 레이아웃이 필요한 요소의 수로, 페이지의 DOM 크기의 부산물입니다.
- 레이아웃의 복잡성
요약
- 레이아웃이 상호작용 지연 시간에 직접적인 영향을 미칩니다.
- 레이아웃은 일반적으로 전체 문서에 적용됩니다.
- DOM 요소 수는 성능에 영향을 미치므로 가능하면 레이아웃 트리거를 피해야 합니다.
- 강제 동기식 레이아웃과 레이아웃 트래싱을 피하세요. 스타일 값을 읽은 후 스타일을 변경합니다.
레이아웃이 상호작용 지연 시간에 미치는 영향
사용자가 페이지와 상호작용할 때 이러한 상호작용은 최대한 빨라야 합니다. 상호작용이 완료되는 데 걸리는 시간(브라우저가 다음 프레임을 표시하여 상호작용 결과를 표시할 때 종료됨)을 상호작용 지연 시간이라고 합니다. 이는 다음 페인트에 대한 상호작용 측정항목에서 측정하는 페이지 성능의 한 측면입니다.
브라우저가 사용자 상호작용에 응답하여 다음 프레임을 표시하는 데 걸리는 시간을 상호작용의 표시 지연이라고 합니다. 상호작용의 목표는 사용자에게 어떤 일이 발생했음을 알리기 위한 시각적 피드백을 제공하는 것이며, 시각적 업데이트는 이 목표를 달성하기 위해 일정량의 레이아웃 작업이 필요할 수 있습니다.
웹사이트의 INP를 최대한 낮게 유지하려면 가능하면 레이아웃을 피하는 것이 중요합니다. 레이아웃을 완전히 피할 수 없는 경우 브라우저가 다음 프레임을 빠르게 표시할 수 있도록 레이아웃 작업을 제한하는 것이 중요합니다.
가능한 한 레이아웃을 피하세요.
스타일을 변경하면 브라우저는 변경사항 중 레이아웃을 계산하고 렌더링 트리를 업데이트해야 하는지 확인합니다. width
, height
, left
, top
와 같은 '기하학적 속성'을 변경하려면 모두 레이아웃이 필요합니다.
.box {
width: 20px;
height: 20px;
}
/**
* Changing width and height
* triggers layout.
*/
.box--expanded {
width: 200px;
height: 350px;
}
레이아웃은 거의 항상 전체 문서에 적용됩니다. 요소가 많으면 모든 요소의 위치와 크기를 파악하는 데 시간이 오래 걸립니다.
레이아웃을 피할 수 없는 경우 Chrome DevTools를 다시 사용하여 걸리는 시간을 확인하고 레이아웃이 병목 현상의 원인인지 확인하는 것이 중요합니다. 먼저 DevTools를 열고 타임라인 탭으로 이동한 다음 '기록'을 누르고 사이트와 상호작용합니다. 녹화를 중지하면 사이트 실적 분석이 표시됩니다.

이전 예시의 트레이스를 자세히 살펴보면 각 프레임의 레이아웃 내에서 28밀리초가 넘게 소요되는 것을 확인할 수 있습니다. 애니메이션에서 화면에 프레임을 표시하는 데 16밀리초가 소요되는 점을 감안할 때 훨씬 너무 긴 시간입니다. DevTools에서 트리 크기 (이 경우 1,618개 요소)와 레이아웃이 필요한 노드 수를 확인할 수도 있습니다 (이 경우 5개).
일반적으로 레이아웃은 가능한 한 피하는 것이 좋지만 항상 레이아웃을 피할 수 있는 것은 아닙니다. 레이아웃을 피할 수 없는 경우 레이아웃 비용은 DOM 크기와 관련이 있다는 점에 유의하세요. 두 항목 간의 관계가 밀접하게 결합되지는 않지만 일반적으로 DOM이 클수록 레이아웃 비용이 더 많이 듭니다.
강제 동기 레이아웃 피하기
프레임을 화면으로 배송하는 순서는 다음과 같습니다.

먼저 JavaScript가 실행되고 그런 다음 스타일 계산이 실행되고 그런 다음 레이아웃이 실행됩니다. 하지만 JavaScript를 사용하여 브라우저가 더 일찍 레이아웃을 실행하도록 강제할 수는 있습니다. 이를 강제 동기식 레이아웃 (또는 강제 리플로)이라고 합니다.
먼저 JavaScript가 실행되면 이전 프레임의 모든 이전 레이아웃 값이 알려져 있으므로 쿼리할 수 있습니다. 예를 들어 프레임 시작 부분에 요소('상자'라고 하겠습니다)의 높이를 작성하려면 다음과 같은 코드를 작성할 수 있습니다.
// Schedule our function to run at the start of the frame:
requestAnimationFrame(logBoxHeight);
function logBoxHeight () {
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
}
상자의 높이를 요청하기 전에 상자의 스타일을 변경하면 문제가 발생합니다.
function logBoxHeight () {
box.classList.add('super-big');
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
}
이제 높이 질문에 답변하려면 브라우저가 super-big
클래스를 추가했기 때문에 먼저 스타일 변경사항을 적용한 후에 레이아웃을 실행해야 합니다. 그래야만 올바른 높이를 반환할 수 있습니다. 이는 불필요하며 비용이 많이 들 수 있습니다.
따라서 항상 스타일 읽기를 일괄 처리하고 먼저 실행한 후 (브라우저가 이전 프레임의 레이아웃 값을 사용할 수 있는 경우) 쓰기를 실행해야 합니다.
이전 함수의 더 효율적인 버전은 다음과 같습니다.
function logBoxHeight () {
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
box.classList.add('super-big');
}
대부분의 경우 스타일을 적용한 다음 값을 쿼리할 필요가 없습니다. 마지막 프레임의 값을 사용하면 충분합니다. 스타일 계산과 레이아웃을 브라우저가 원하는 것보다 일찍 동기식으로 실행하는 것은 병목 현상을 일으킬 수 있으므로 일반적으로 권장되지 않습니다.
레이아웃 스래싱 방지
강제 동기식 레이아웃을 더욱 악화시키는 방법이 있습니다. 빠르게 연속으로 많이 실행하는 것입니다. 다음 코드를 살펴보세요.
function resizeAllParagraphsToMatchBlockWidth () {
// Puts the browser into a read-write-read-write cycle.
for (let i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.width = `${box.offsetWidth}px`;
}
}
이 코드는 여러 단락 그룹을 반복하고 각 단락의 너비를 '상자'라는 요소의 너비와 일치하도록 설정합니다. 무해해 보이지만 문제는 루프의 각 반복이 스타일 값 (box.offsetWidth
)을 읽은 다음 즉시 이를 사용하여 단락의 너비 (paragraphs[i].style.width
)를 업데이트한다는 점입니다. 루프의 다음 반복에서 브라우저는 offsetWidth
가 마지막으로 요청된 이후 (이전 반복) 스타일이 변경되었다는 사실을 고려해야 하므로 스타일 변경사항을 적용하고 레이아웃을 실행해야 합니다. 이는 모든 반복에서 발생합니다.
이 샘플의 해결 방법은 값을 다시 읽은 다음 쓰는 것입니다.
// Read.
const width = box.offsetWidth;
function resizeAllParagraphsToMatchBlockWidth () {
for (let i = 0; i < paragraphs.length; i++) {
// Now write.
paragraphs[i].style.width = `${width}px`;
}
}
강제 동기식 레이아웃 및 트래싱 식별
DevTools에는 강제 동기식 레이아웃('강제 리플로'라고도 함)의 사례를 빠르게 식별하는 데 도움이 되는 강제 리플로 통계가 있습니다.

강제 동기식 레이아웃은 forcedStyleAndLayoutDuration
속성을 사용하여 Long Animation Frame API 스크립트 저작자 표시를 사용하여 필드에서 식별할 수도 있습니다.