[번역] JavaScript를 활용한 의도적인 렌더링 차단

I
Inkyu Oh

Front-End2026.06.10

Jay Freestone - 2026-05-16


렌더링 전 브라우저 페이지의 페인트 레이어를 일시 중지하는 작은 스크립트 블록의 등각 투영 일러스트레이션.

'올바른' 레이아웃이나 마크업을 렌더링하기 위해 클라이언트 측 JavaScript에 의존하는 UI 컴포넌트가 있다고 가정해 봅시다. (끝까지 들어보세요. 컨테이너 쿼리(Container queries)만으로는 해결되지 않는 경우가 있습니다.)
이 경우 선택지는 사실상 세 가지뿐입니다.
  • JS가 로드되어 스타일이 적용되기 전까지 스타일이 적용되지 않은 컴포넌트가 노출되는 '플래시(Flash)' 현상을 수용합니다.
  • 스크립트가 컴포넌트를 드러낼 때까지 숨깁니다. (이 방식은 달성하려는 목적에 따라 레이아웃 시프트(Layout shift)를 유발할 수 있습니다.)
  • 렌더링 차단(Render-blocking) JS를 사용하여 사용자가 무언가 잘못된 것을 알아채기 전에 '페인트(Paint)보다 빠르게' 모든 것을 제자리에 배치합니다.
전통적인 인라인 스크립트(그리고 asyncdefer가 없는 외부 스크립트)는 파서 차단(Parser-blocking) 방식입니다. 이는 스크립트가 파싱되고 평가될 때까지 HTML 파서가 그 아래의 내용을 읽지 못하도록 차단됨을 의미하며, 따라서 아래의 어떤 내용도 페인트될 수 없습니다.
하지만 브라우저는 그 시점까지 수신된 청크(Chunks)를 여전히 페인트하기로 선택할 수 있습니다. 따라서 다음과 같이 작성하더라도 '플래시' 현상을 피할 수 있다는 보장은 없습니다.
<my-component>레이아웃 측정이 필요합니다</my-component>

<script>
class MyComponent extends HTMLElement {
// ...
}

customElements.define("my-component", MyComponent);
</script>
차단 스크립트를 컴포넌트 위로 옮기면, (아직 파싱되지 않은) 자식 요소들을 읽을 수 없게 됩니다.
<script>
class MyComponent extends HTMLElement {
constructor() {
super();
const inner = this.querySelector('.inner');
// 너무 빠릅니다.
console.log('constructor', { inner });
}

connectedCallback() {
const inner = this.querySelector('.inner');
// 여전히 너무 빠릅니다. 자식 요소들이 파싱되어
// DOM에 부착되기 전에 엘리먼트가 연결되기 때문입니다.
console.log('connectedCallback', { inner });
}
}

customElements.define("my-component", MyComponent);
</script>

<my-component>
<span class="inner">Thing</span>
</my-component>
아래 버전은 파서가 완료된 후에 컴포넌트 등록을 지연시키므로 작동할 것입니다.
<script>
class MyComponent extends HTMLElement {
constructor() {
super();
const inner = this.querySelector('.inner');
// 작동합니다.
console.log('constructor', { inner });
}

connectedCallback() {
const inner = this.querySelector('.inner');
// 역시 작동합니다.
console.log('connectedCallback', { inner });
}
}
</script>

<my-component>
<span class="inner">Thing</span>
</my-component>

<script>
customElements.define("my-component", MyComponent);
</script>
하지만 여전히 my-component가 기본 상태로 렌더링되지 않을 것이라고 보장할 수는 없습니다.

blocking="render"

스크립트 태그에는 우리가 원하는 것을 정확히 수행하는 깔끔하고 지원 범위도 꽤 넓은 속성이 있습니다. 바로 blocking="render"입니다.
<script>, <style> 또는 스타일시트 <link>에 'blocking=render'를 속성과 값으로 추가하여 명시적으로 렌더링을 차단할 수 있게 합니다. 주요 용도는 스크립트로 삽입된 스크립트/스타일시트, 클라이언트 측 A/B 테스팅 등으로 인해 발생하는 스타일이 적용되지 않은 콘텐츠의 플래시나 미완성된 페이지와의 사용자 상호작용을 방지하는 것입니다. — Chrome Platform Status
이제 다음과 같이 작성하면 스크립트가 로드될 때까지 아무것도 페인트되지 않음을 확실히 보장할 수 있습니다.
<my-component>
<span class="inner">Thing</span>
</my-component>

<script blocking="render">
class MyComponent extends HTMLElement {
// ...
}
customElements.define("my-component", MyComponent);
</script>
이는 type="module"과도 함께 작동합니다. (전역 네임스페이스를 오염시킬 필요가 없습니다.)
<script type="module" blocking="render">
class MyComponent extends HTMLElement {
// ...
}
customElements.define("my-component", MyComponent);
</script>
외부 스크립트에서도 작동합니다.
<script type="module" blocking="render" src="/js/my-component.js"></script>
멋진 점은 렌더링이 차단되더라도 파서는 여전히 자유롭게 진행될 수 있다는 것입니다. 이는 전통적인 차단 스크립트 방식보다 크게 진보한 부분입니다.

하지만 왜일까요?

렌더링이나 파싱을 차단하는 것은 대개 최선의 선택이 아닙니다. 가능한 한 빨리 무언가를 보여주고 나중에 점진적 향상(Progressive enhancement)을 적용하는 것이 거의 항상 더 낫습니다.
그럼에도 불구하고 타당한 유즈케이스들이 있습니다. Chrome 팀과 Harry Roberts가 언급한 A/B 테스팅이 그 예인데, 외부 스크립트가 페이지의 완전히 다른 버전을 보여줘야 할 수도 있기 때문입니다.
또한, 의미 있는 구성을 위해 레이아웃에 의존할 수밖에 없는 작은 컴포넌트들에게도 완벽한 해결책입니다.

실질적인 예시

넘치는 내비게이션 항목이 화면 밖 팝오버로 이동하는 프라이어리티 플러스 내비게이션 패턴의 예시

가장 중요한 내비게이션 요소는 계속 표시되는 반면, 나머지 항목들은 화면 밖의 팝오버/모달/드로어(Drawer)로 계속해서 '이동'합니다.
크기를 알 수 없는 가변적인 수의 내비게이션 요소가 주어졌을 때, 실제로 페이지에 배치되기 전까지는 얼마나 많은 요소가 '들어갈지' 알 수 없습니다. 넘치는 내비게이션 요소는 (동작/스타일뿐만 아니라 접근성(a11y)을 위해서도) DOM에서 렌더링되는 위치를 변경해야 하므로, CSS 트릭만으로는 해결할 수 없습니다.
이는 다음과 같은 인라인 차단 스크립트를 사용하기에 완벽한 사례입니다.
  • 내비게이션이 DOM에 단일 리스트로 미리 존재합니다.
  • 렌더링 차단 스크립트가 공간을 측정하고 넘치는 내비게이션 요소를 오버플로우 영역으로 이동시킵니다.
  • 렌더링 차단이 해제됩니다.
플래시 현상도 없고, (눈에 보이는) 레이아웃 시프트도 발생하지 않습니다.

결론

때로는 공격적인 레이아웃 시프트를 피하기 위해 인라인 렌더링 차단 스크립트를 사용하는 것이 작은 대가일 수 있습니다.
다만 스크립트는 작아야 하며, 가급적 인라인이어야 합니다. 네트워크 호출을 도입하는 순간 상당한 오버헤드가 발생하기 때문입니다.
0
1

댓글

?

아직 댓글이 없습니다.

첫 번째 댓글을 작성해보세요!

Inkyu Oh님의 다른 글

더보기

유사한 내용의 글