웹 이미지 실전 — 크기·품질·로딩을 정하는 순서

각 포맷이 무엇에 강하고 약한지는 웹 이미지 포맷 고르기에서 다뤘습니다. 이번 편은 “그래서 실제로 어떤 순서로 정하느냐”입니다.

포맷보다 먼저: 몇 픽셀이 필요한가

포맷을 WebP로 바꾸면 25~35% 줄어듭니다. 그런데 4000px 사진을 800px 자리에 쓰고 있었다면, 크기를 맞추는 것만으로 90% 넘게 줄어듭니다. 순서가 반대면 큰 쪽을 놓칩니다.

필요한 픽셀 수는 두 가지를 곱한 값입니다.

  1. CSS 기준 표시 폭 — 개발자도구에서 이미지를 선택하면 나옵니다
  2. 화면 배율 — 고해상도 화면은 CSS 1px에 물리 픽셀을 2개 씁니다

800px 자리에 2배 화면까지 챙기려면 1600px이면 충분합니다. 그 이상은 내려받는 용량만 늘고 화면에서 달라지는 것이 없습니다.

배율은 브라우저에서 바로 확인할 수 있습니다.

// 1이면 일반 화면, 2면 고해상도 화면
console.log(window.devicePixelRatio);

저는 입사하고 얼마 안 됐을 때 이걸 몰라서 문제를 만든 적이 있습니다. 이미지 크기를 신경 쓰지 않고 받은 그대로 올렸더니 홈페이지 트래픽이 초과됐습니다. 어떤 파일 때문인지 확인해 보니 대부분 크기를 줄이지 않은 큰 이미지였습니다.

실전 1: srcset으로 필요한 것만 내려받기

모든 사람에게 1600px을 내려보내면 폰 사용자가 손해입니다. srcset은 후보를 나열하고, sizes는 그 이미지가 화면에서 얼마나 넓게 놓이는지 알려줍니다. 브라우저가 둘을 보고 알아서 고릅니다.

<img
  src="photo-800.jpg"
  srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
  sizes="(max-width: 600px) 100vw, 800px"
  width="1600" height="900"
  alt="설명"
/>
  • 400w는 파일의 실제 가로 픽셀 수입니다. 표시 크기가 아닙니다
  • sizes는 “600px 이하 화면에서는 화면 폭만큼, 그보다 크면 800px”이라는 뜻입니다
  • src는 srcset을 모르는 환경을 위한 대비책입니다

sizes를 빼먹으면 브라우저는 100vw로 가정해서 필요 이상으로 큰 파일을 고릅니다. srcset을 쓸 거면 sizes도 같이 씁니다.

실전 2: 품질은 눈이 아니라 용량으로 정한다

품질 값을 눈으로만 고르면 대개 필요 이상으로 올려 둡니다. 90과 80은 화면에서 구분하기 어려운데 용량은 눈에 띄게 차이 납니다.

같은 이미지를 몇 단계로 저장해 용량을 나란히 놓고 고르는 것이 빠릅니다. 75~85 사이에서 시작해서, 확대했을 때 거슬리는 부분이 없으면 더 내려 봅니다.

사진 종류에 따라 적정값이 다릅니다.

  • 디테일이 많은 사진(나뭇잎, 군중, 질감) — 낮추면 금방 뭉개집니다. 80 이상
  • 완만한 사진(하늘, 단색 배경, 인물 클로즈업) — 65까지 내려도 잘 버팁니다
  • 글자가 있는 이미지 — 품질 문제가 아니라 포맷 문제입니다. PNG나 무손실로

이것도 직접 겪으면서 알게 됐습니다. 트래픽 초과를 겪은 뒤로 이미지 품질을 낮춰서 올렸는데, 글씨가 많은 이미지는 품질을 많이 낮추면 차이가 확 드러났습니다. 사진에서는 티가 잘 안 나는 값에서도 글자 가장자리는 금방 지저분해집니다.

여러 설정을 비교해 보려면 이미지 포맷 변환기에 사진을 넣고 품질과 크기를 바꿔 가며 결과 용량을 보세요. 파일이 서버로 올라가지 않아 원본을 그대로 두고 시험할 수 있습니다.

실전 3: 이미지 때문에 화면이 튀지 않게

이미지가 늦게 도착하면 그 자리가 갑자기 벌어지면서 읽고 있던 글이 아래로 밀립니다. 검색 순위에도 반영되는 지표(CLS)입니다.

막는 방법은 간단합니다. width와 height 속성을 적어 두는 것입니다.

<img src="photo.jpg" width="1200" height="630" style="width:100%;height:auto" alt="">

CSS로 크기를 다시 정하더라도 속성은 남겨 둡니다. 브라우저가 두 값의 비율로 aspect-ratio를 자동으로 잡아 이미지가 오기 전에 자리를 미리 비워 두기 때문입니다.

실제로 재 보면 차이가 분명합니다. 400px 폭 자리에 놓았을 때,

이미지 도착 전 높이
width·height 속성 있음 210px (400 × 630/1200을 미리 확보)
속성 없음 0px (도착하는 순간 화면이 밀림)

style="width:100%; height:auto"를 함께 주는 이유는, 속성값 그대로 1200px로 그려지지 않게 하면서 비율만 살리기 위해서입니다.

실전 4: 첫 화면 이미지와 나머지를 다르게 다룬다

loading="lazy"는 화면 밖 이미지를 나중에 받게 해서 초기 로딩을 가볍게 합니다. 그런데 첫 화면의 큰 이미지에까지 걸면 오히려 느려집니다. 가장 먼저 보여야 할 것을 나중에 받도록 미루는 셈이기 때문입니다.

<!-- 첫 화면의 대표 이미지: 미루지 않고, 우선순위를 올린다 -->
<img src="hero.jpg" width="1600" height="900" fetchpriority="high" alt="">

<!-- 스크롤해야 보이는 이미지: 미룬다 -->
<img src="below.jpg" width="800" height="600" loading="lazy" alt="">

loading과 fetchpriority는 기본값이 둘 다 auto입니다. 아무것도 적지 않으면 브라우저 판단에 맡기는 것이고, 그것도 대체로 나쁘지 않습니다. 적을 거라면 “첫 화면 = high, 아래쪽 = lazy” 두 가지만 지키면 됩니다.

흔한 실수

  • srcset만 쓰고 sizes를 빼는 것 — 브라우저가 100vw로 가정해 큰 파일을 고릅니다. 줄이려고 넣은 것이 반대로 작동합니다
  • 첫 화면 이미지에 loading="lazy" — 가장 흔한 성능 역효과입니다
  • width·height 속성을 CSS로 대체했다고 지우는 것 — 자리를 미리 잡는 일은 CSS가 아니라 그 속성이 합니다
  • 원본을 손실 포맷으로만 보관하는 것 — 다시 저장할 때마다 나빠집니다. 원본은 무손실로 두고 내보낼 때만 손실 포맷으로 바꿉니다
  • 투명한 PNG를 그대로 JPG로 바꾸는 것 — 변환 도구에 따라 투명한 부분이 검게 나옵니다. 흰 배경을 먼저 깔아야 합니다
  • 장식용 이미지에 alt 텍스트를 채우는 것 — 뜻이 없는 이미지는 alt=""로 비워야 낭독에서 건너뜁니다. 지우는 게 아니라 비우는 것입니다

투명한 배경 때문에 겪은 일이 하나 있습니다. 클라이언트가 배경이 하얀 이미지만 올릴 거라고 생각하고, 작업할 때 넣어 둔 테스트용 배경색을 지우지 않았습니다. PNG와 JPG의 차이를 잘 모르는 클라이언트라는 걸 생각하지 못한 겁니다. 그런데 배경이 없는 PNG가 올라오자 투명한 부분으로 그 테스트 배경색이 그대로 비쳐 보였습니다. 이미지가 들어갈 자리에는 투명한 파일이 올라올 수도 있다고 보고, 그 뒤에 깔린 배경색까지 확인해 두어야 합니다.

요약

  • 크기를 먼저, 포맷을 나중에. 표시 폭 × 화면 배율이 필요한 픽셀 수다
  • srcset은 후보, sizes는 놓이는 폭. 둘은 같이 쓴다
  • 품질은 75~85에서 시작해 용량을 보고 내린다. 사진 종류에 따라 다르다
  • width·height 속성이 자리를 미리 잡는다. 400px 자리에서 210px 대 0px의 차이
  • 첫 화면 이미지는 lazy를 걸지 않는다. 필요하면 fetchpriority="high"
  • 원본은 무손실로 보관하고, 내보낼 때만 손실 포맷으로 바꾼다