junglast
Published on

<img>의 width/height 속성과 페이지 렌더링의 상관관계

<img>, <svg>, <video> 등 일부 HTML 요소에는 widthheight 속성으로 요소의 크기를 지정할 수 있습니다. 사실 아주 과거에는 <table width="400" height="300"> 등과 같이 HTML 요소에 직접적으로 widthheight 속성을 사용해 크기를 지정하는 것이 가능했지만, 스타일링과 관련된 코드는 별도의 CSS에 분리하게 되면서 HTML5에서는 일부 요소를 제외하고 대부분의 요소에서 widthheight 속성은 삭제되었습니다.

이렇게 웹 문서의 마크업과 스타일링이 명확하게 분리된 모던 웹 환경에서 <img> 등의 요소에 widthheight 속성이 남겨진 이유가 궁금했었는데, 실제 브라우저가 페이지를 렌더링하는 과정에서 이 widthheight 속성이 생각보다 중요한 의미를 갖는다는 것을 알게 되어 관련 내용을 간단히 정리해보았습니다.

크기를 명시하지 않았을 때 일어나는 일

페이지가 로드될 때 브라우저는 HTML을 파싱하면서 중간에 외부 리소스(<img>, <link> 등)를 만난다면 이를 별도의 스레드에서 다운로드 합니다. 따라서 이미지가 다운로드 되지 않은 경우에도 브라우저는 파싱한 HTML과 CSS를 통해 레이아웃을 만들고 이를 통해 화면을 그릴 수 있습니다.

아래 예시처럼 이미지에 widthheight를 명시하지 않았다면, 이미지가 완전히 다운로드 되기 전까지는 문서에 아무 내용도 표시되지 않습니다. 하지만 다운로드가 완료된 후에는 이미지의 크기만큼 본문 내용이 아래로 밀려난채로 표시됩니다. 이미지를 표시하기 위해서 얼마만큼의 공간을 확보해야 하는지 브라우저가 미리 알 수 있는 방법이 없기 때문입니다.

이미지 다운로드 완료 전
이미지 다운로드 완료 후

따라서 이미지의 다운로드 이후 주변 레이아웃이 갑자기 변경되기 때문에 페이지를 보고있던 사용자의 경험에 안 좋은 영향을 끼칠 수 있을 뿐만 아니라, 브라우저 역시 이미지를 표시할 공간을 마련하기 위해 주변 레이아웃을 다시 계산해야 하므로 성능적인 측면(소위 Cumulative Layout Shift 문제)에서 문제가 발생할 수 있습니다.

해외의 한 블로그 포스팅에 따르면 100개의 이미지를 포함하고 있는 웹 문서를 대상으로 widthheight 속성 유무의 차이를 분석한 결과, 브라우저가 레이아웃 계산에 사용하는 시간이 유의미한 차이를 보인다고 합니다.

좌측은 크기를 지정했을 때, 우측은 지정하지 않았을 때

출처: https://www.smashingmagazine.com/2020/03/setting-height-width-images-important-again/

CSS로 크기 지정을 할 때

HTML의 width, height 속성과 동일하게 CSS의 width, height 값을 사용해도 동일한 효과를 얻을 수 있습니다. 특히, HTML과 CSS에 모두 크기를 지정했다면 일반적으로 CSS에 지정한 값이 HTML에 지정한 값을 덮어씁니다.

물론 HTML이나 CSS 중 한 곳에만 크기가 지정되었더라도 브라우저가 레이아웃을 생성할 때 이미지를 위해 내주어야 할 공간을 정확히 계산할 수 있으므로 레이아웃을 재계산하는 문제가 일어나지 않습니다.

하지만 여기서 이미지의 비율 유지를 위해 widthheightauto와 같은 수치를 사용하면 문제가 복잡해질 수 있습니다.

레이아웃 재계산(reflow)가 발생하지 않기 위한 조건

결국 브라우저가 레이아웃을 재계산하지 않게 하려면 이미지 등 에셋이 다운로드 완료되기 이전부터 해당 에셋이 레이아웃 내에서 차지할 크기를 정확히 알기만 하면 됩니다. 이러한 크기를 정확히 알 수 있다는 것은 다음 두 가지 경우일 것입니다.

1. 이미지의 가로 크기와 세로 크기를 모두 명시하는 경우

앞선 예제 처럼 HTML이나 CSS 중 최소 한 곳에 이미지의 가로 크기와 세로 크기를 명시하면 브라우저는 당연하게도 해당 이미지가 차지할 크기를 미리 알 수 있습니다.

2. 이미지의 가로 크기나 세로 크기 중 한 가지를 절대 수치로 알고, 동시에 이미지의 가로/세로 비율을 아는 경우

이미지의 가로/세로 크기 중 한 곳의 절대 수치만 알고 있다고 하더라도, 해당 이미지의 가로/세로 비율을 알고 있다면 이미지가 차지할 크기를 미리 알 수 있습니다.

<style>
  #main-img {
    aspect-ratio: 4/3;
  }
</style>
...

<p>이미지 위 텍스트</p>
<img
  id="main-img"
  src="https://images.pexels.com/photos/12007906/pexels-photo-12007906.jpeg"
  width="800"
/>
<p>이미지 아래 텍스트</p>

위 경우 이미지의 세로 길이가 지정되어 있지 않더라도 가로/세로의 비율이 4:3으로 지정되어 있으므로 브라우저는 사전에 세로 길이를 600으로 계산할 수 있습니다.

하지만 아래와 같은 경우는 문제가 발생합니다.

<style>
  #main-img {
    width: 100%;
    height: auto;
  }
</style>
...

<p>이미지 위 텍스트</p>
<img id="main-img" src="https://images.pexels.com/photos/12007906/pexels-photo-12007906.jpeg" />
<p>이미지 아래 텍스트</p>

CSS 영역에는 이미지의 가로 크기를 부모 컨테이너의 크기만큼 설정하기 위해 width100%를 지정하고, 이미지의 비율을 유지하기 위해 heightauto를 지정했습니다. 결과적으로 CSS에 지정한 값만으로는 이미지가 차지할 공간의 가로 크기는 알 수 있지만, 이미지의 가로/세로 비율을 알 수 없어 이미지가 차지할 공간의 세로 크기를 계산할 수 없으므로 브라우저는 이미지를 다운로드 완료한 이후 레이아웃을 다시 계산해야 합니다. 이와 같은 경우에 <img /> 요소에 직접 widthheight를 지정하는 것이 페이지 렌더링과 사용자 경험 측면에서 이점을 가져올 수 있습니다.