이번에는 웹 개발에서 이미지를 어떻게 다룰지에 대해 알아보고자 합니다.
오늘날 웹 환경에서 가장 많은 데이터를 차지하는 것은 이미지입니다.
이제는 이미지를 사용하지 않은 웹 페이지는 사실상 없죠. 대부분의 사이트에서 트래픽의 80% 이상은 이미지라고 보아도 무방합니다.
요즘 시대에 이미지가 없는 블로그나 쇼핑몰을 상상해보면.. 정말 지루하고, 보고싶지도 않겠죠?
그만큼 이미지는 사용자의 경험을 높이는 데에 정말 큰 역할을 합니다.
하지만 이미지 리소스를 사용하는 것은 그만큼 많은 데이터를 사용하고, 서버와 네트워크에 부하를 주기도 합니다.
특히 최근들어 수많은 경쟁을 뚫고 나타나는 고성능 모바일 기기들은 한장에 수십 MB에 달하는 이미지를 생산해 내고 있어요.
iPhone 16Pro, 일반 이미지 촬영시 5~10mb, Raw 이미지 촬영 시 보통 20mb 이상의 이미지가 나오네요.
이러한 환경에서, 이미지를 최적화하여 사용자 경험을 향상시키고 서버 부하를 줄이는 것은 매우 중요한 일입니다.
그렇다면 이미지는 무조건 작은것을 쓰는 게 좋을까요?
당연하게도, 서비스의 전반적인 인상과 신뢰도를 위해서는 품질 좋은 이미지를 활용하는 것도 굉장히 중요하죠.
- 만약 본인이 가방을 사러 사이트에 방문한 고객이라면, 왼쪽과 오른쪽 쇼핑몰 중 어떤 판매자의 상품을 구매할까요?
결론적으로, 우리는 앱 전반에 걸쳐서 '용량은 작으면서도 화질은 좋은' 이미지를 사용하기위해 최적화를 해야합니다.
이를 다시 정리해보면 아래와 같습니다.
쿠팡의 이미지 요청 기록. 약 900여개의 요청 중에 1mb가 넘는 이미지는 하나 뿐이다.>이 외에도 effort와 같은 개념도 존재하지만, 여기서는 다루지 않겠습니다.
JPEG는 손실 압축을 사용하는 이미지 포맷입니다.JPEG 퀄리티 값은 단순한 퍼센트가 아닌 수학적 공식에 기반한 '변수'이고, 이를 통해 파일의 크기와 품질이 결정됩니다.JPEG의 손실 압축이 이러한 현상을 일으킵니다.PNG 설명에서 '자세히 알아보기: 로고와 텍스트에 PNG가 적합한 이유'를 통해 더 이야기 해보겠습니다.
CMYK 색상 모델을 지원하므로, 프린트용 이미지로도 사용할 수 있습니다.TIFF등을 사용하는 것이 일반적이지만, 그런것을 사용하는 분이라면 이미 저보다 잘 알고 계실 것 같네요주된 용도: 중·소형 이미지에 적합하며, 중간 정도의 품질에서 파일 크기와 화질 간의 균형이 좋습니다. 웹 사진, 블로그 포스트 등에 주로 사용됩니다.
부적절한 용도: 알파 채널(투명도)이 필요한 이미지나 매우 높은 품질이 중요한 그래픽에는 적합하지 않습니다.
많은 분들이 이미지의 퀄리티를 퍼센트의 개념으로 오해하고 있습니다.
그러나, JPEG의 설명 맨 첫줄에서 보셨듯이, JPEG는 손실 압축을 사용하는 이미지 포맷입니다.
따라서 JPEG는 원본 데이터를 모두 가지고있지 않고, JPEG는 퍼센트의 개념으로 화질을 표현하는 것이 태생적으로 불가능합니다.
이를 좀 더 구체적으로 이야기하자면, 퀄리티를 70으로 내렸다가 다시 100으로 올린다고 해서 원본 이미지의 퀄리티를 되찾을 수 없으며, 심지어 다른 포멧의 이미지를 퀄리티 100으로 저장한다 해도 원본 이미지와 동일한 데이터를 가졌다고 보장 할 수 없다는 것입니다.
퀄리티를 100으로 설정할 경우, 파일 크기가 급격히 증가하지만 품질 향상은 느낄 수 없으며, 단지 더 비싼 모자이크된 이미지를 얻게 될 뿐입니다.
이러한 이유로, 우리는 적절한 타협점을 찾아야 합니다. 그리고 퀄리티 75가 바로 파일 크기와 품질의 균형을 맞춘 '스위트 스팟'입니다. 이 이상으로 퀄리티를 높인다 해도 대부분의 경우 파일의 크기만 커지고 품질 향상은 느낄 수 없습니다.


약간의 욕심을 부린다면 퀄리티 80 정도로 설정해도 괜찮을 테지만 그 이상은 과욕입니다.
PNG는 비손실 압축을 사용하는 이미지 포맷입니다.PNG는 텍스트나 로고와 같이 선명한 경계를 가진 그래픽에 적합합니다.주된 용도: 매우 큰 이미지, 품질이 중요한 이미지, 투명도가 필요한 그래픽에 적합합니다. 로고, 아이콘, 일러스트레이션 등에 주로 사용됩니다.
부적절한 용도: 파일 크기가 중요한 경우, 예를 들어 웹 페이지 로딩 속도가 중요한 경우에는 부적합 합니다.
앞서 설명한 것처럼, PNG는 투명도를 지원하고, 이미지의 품질을 손상시키지 않는 비손실 압축을 사용하는 이미지 포맷입니다.
이러한 특성 때문에 PNG는 로고나 텍스트와 같이 선명한 경계를 가진 이미지에 적합한데요, 이는 JPEG와 비교해 본다면 좀 더 명확하게 이해할 수 있습니다.
계속 이야기했듯이, JPEG는 손실 압축을 사용하는 이미지 포맷입니다.
특히 아래와 같은 DCT(Discrete Cosine Transform) 테이블과, 첨부하지는 않았지만 양자화 테이블(Quantization Table)을 사용하는데요, 덕분에 복잡한 이미지를 비교적 작은 용량으로 저장할 수 있습니다.


양자화 테이블은 굳이 꺼내지 않았지만, DCT 테이블은 하나의 꿀팁을 위해 꺼내왔습니다.
JPEG는 이미지를 8x8 픽셀 블록으로 나누어 DCT를 적용하는데, 이 때 사용되는 DCT 테이블은 사실상 해당 블록의 픽셀을 뭉개버리는 것과 같습니다.
그런데 만약 이 뭉개짐이 텍스트나 로고와 같이 선명한 경계를 가진 이미지에 적용된다면, 이러한 경계가 흐릿해지거나, 뭉개지는 현상이 발생할 수 있습니다.
특히 여러 번 중복 저장을 하게 된다면, 이러한 현상은 더욱 심해질 수 있겠죠. 이게 바로 '디지털 풍화'라는 현상입니다.



위의 이미지를 보시면, JPEG로 저장한 이미지는 텍스트의 경계가 흐릿해지고, 배경과 텍스트의 경계가 뭉개지는 현상이 발생합니다. 특히 글자 주변에 검은 점이 곳곳에 발생했네요.
특히 162x41 이미지의 경우, 단 2픽셀 차이이고 크기를 오히려 더 덜 줄였음에도 'ford'등의 부분에서 오히려 글자들이 더 흐릿해진 것을 볼 수 있습니다.
반면 PNG의 경우에는 비록 크기를 너무 줄인탓에 글자는 흐려졌을지언정, 주변부에 지저분한 잔상은 남지 않았습니다. 매우 깔끔한 배경을 보실 수 있죠.
이처럼 단색 배경이나 패턴의 반복 등, 단순한 이미지의 경우에는 앞서 말씀드린 '딕셔너리 기반 압축 알고리즘'의 특성상 매우 효율적인 압축률을 보여 오히려 JPEG보다 용량이 작아질 수도 있습니다.
이러한 이유로, 로고나 텍스트와 같이 선명한 경계를 가진 이미지에는 PNG가 적합하며, 이러한 이미지를 사용할 경우 JPEG보다 더 나은 품질을 제공할 수 있습니다.
GIF는 256색의 제한된 색상 팔레트를 사용하는 비손실 압축 이미지 포맷입니다.PNG와 달리 반투명(부분적 투명도)은 지원하지 않습니다.주된 용도: 짧은 애니메이션, 간단한 움직임을 표현하는 그래픽에 적합합니다. 밈, 로딩 스피너 등에 주로 사용됩니다.
부적절한 용도: 색상이 복잡하거나 높은 품질이 요구되는 이미지에는 부적합 합니다. 정적인 이미지의 경우, 다른 포맷을 사용하는 것이 더 나은 품질과 효율성을 제공합니다.
WEBP는 구글에서 개발한 이미지 포맷으로, JPEG와 PNG의 장점을 모두 가지고 있습니다.JPEG보다 약 30% 더 작은 파일 크기를 제공합니다.WEBP를 비손실 고퀄리티로 사용할 경우, 오히려 PNG보다 파일 크기가 커질 수 있습니다. 이는 비손실 압축이 특정 이미지에 대해 비효율적일 수 있기 때문입니다.WEBP는 퀄리티 65-75 정도에서 파일 크기와 화질 간의 균형이 가장 좋은 '스위트 스팟'을 갖습니다.GIF보다 더 나은 대안이 될 수 있습니다.주된 용도: 파일 크기를 줄여야 하는 웹 환경에서 유용하며, 일반적인 웹 이미지를 대상으로 합니다. 중·소형 크기의 이미지에 적합합니다.
부적절한 용도: 대형 이미지나, 품질이 중요한 경우. 혹은 모든 사용자가 최신 브라우저를 사용하지 않는 환경에서는 부적합합니다.
AVIF는 AV1 비디오 코덱을 기반으로 한 이미지 포맷입니다.AVIF는 퀄리티 50-60 정도에서 '스위트 스팟'을 갖습니다.CanIUse 기준) 브라우저에서도 지원 범위가 다를 수 있습니다.주된 용도: 파일 크기와 화질을 최대한 줄이고자 할 때 유용하며, 최신 웹 환경에서 이미지 최적화에 유리합니다. 중·소형 크기의 이미지에 적합합니다.
부적절한 용도: 대형 이미지나 품질이 매우 중요한 이미지, 혹은 모든 사용자가 최신 브라우저를 사용하지 않는 경우에는 부적합합니다.
⚠️ 흔히 '이제 대부분의 브라우저에서 동작합니다' 라고 홍보하지만, 생각보다 iOS 등의 지원 구멍이 많으니 주의가 필요합니다!
앞서 말한것과 같이, 이미지의 크기를 적절히 조절하는 것이 이미지 최적화의 첫걸음입니다.
특히 최근 모바일 기기나 카메라의 발전으로 인해 대부분의 이미지는 과도하게 큰 해상도를 가지고 있고, 많은 사람들이 '이정도는 너무 작은것 아니야?'라고 생각하기도 합니다.


사실 벨로그에서는 둘다 똑같이 보여질겁니다.
하지만 대부분의 웹 환경에서 페이지가 실제로 그려지는 영역의 폭은 평균적으로 1200px 정도이며, 모바일에서는 400-600px 정도도 충분합니다. 정말 큰 경우에도 1920px 정도에 그치죠.
게다가 그 영역 안에 이미지가 가득 차야하는 경우는 더욱 드물구요.
또한 생각보다 사람들은 이미지의 해상도에 대해 그렇게까지 민감하지 않습니다.
물론 제품 판매 페이지의 상세보기 이미지나, 블로그 포스트의 특정 이미지 등에는 높은 해상도가 필요할 수 있겠지만, 그런 이미지는 직접 사용해보고 피드백을 받아보는 것이 가장 좋습니다.
그리고 또 하나 신경써야 할 부분은 브라우저의 렌더링입니다.
단순히 큰 이미지가 페이지에 존재하는 것만으로도 브라우저는 그 이미지를 렌더링하기 위해 메모리를 할당하고, 렌더링을 위한 작업을 수행합니다. 흔히들 말하는 버벅임이 발생하는 원인 중 하나가 바로 이러한 과도하게 큰 이미지의 크기 때문이기도 합니다.
이러한 이유로, 가장 먼저 해야 할 일은 이미지의 크기를 적절히 조절하는 것입니다.
또 한가지 고려해야 할 부분은 이미지 포맷입니다. 그리고 생각보다 신경써야 할 부분도 많죠.
이미지 포맷은 이미지의 특성에 따라 적절한 포맷을 선택하는 것이 중요합니다. 위에서 언급했던 각 포멧별 특성을 잘 알아두시고, 이미지의 특성에 맞는 포맷을 선택하는 것이 좋습니다.
그리고 꼭 이미지의 호환성도 고려해야 합니다. 세상에는 정말 수도없이 다양한 디바이스와 브라우저가 존재하며, 이들이 모두 같은 이미지 포맷을 지원하는 것은 아닙니다.
우리는 모든 이미지를 WEBP로 처리할테야! 라고 생각하다가 엉뚱한 브라우저에서 고객에게 문제가 생긴다면 참 골치가 아프실 겁니다.
그리고 포멧을 변경 할 때 반드시 필요한 과정이 바로 품질 조절입니다.
위에서 언급했듯이, 이미지의 특성별, 용도별로 수많은 선택지가 있습니다. 제가 제시한 스위트 스팟을 그대로 사용하셔도 좋겠지만, 각자 도메인에 맞게 테스트를 진행하시고, 사용자의 피드백을 받아보는 것이 가장 좋습니다.
계속 언급했듯이, 이미지 최적화의 핵심은 사용자의 디바이스와 네트워크 환경에 맞는 이미지를 제공하는 것입니다.
HTML의 반응형 이미지 기능을 활용하면, 브라우저가 자동으로 최적의 이미지를 선택 할 수 있도록 도움을 줄 수 있습니다.
<Picture> 요소를 사용한 포멧 대응<picture>
<source type="image/avif" srcset="some-image.avif">
<source type="iamge/webp" srcset="some-image.webp">
<img src="image/jpg" alt="description">
</picture>
이러한 Picture 요소를 사용하면, 브라우저는 상단의 이미지부터 사용여부를 판단하여 처리할 수 있는 이미지를 사용합니다.
AVIF를 지원한다면 AVIF를, WEBP를 지원한다면 WEBP를 사용하고, 아무것도 지원하지 않는 구형 브라우저라면 JPG를 로드해서 사용합니다.
<img srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
sizes="(max-width: 600px) 480px, 800px"
src="medium.jpg" alt="description">
srcset을 사용하면 디바이스의 픽셀 밀도와 뷰포트 크기에 따라 적절한 이미지를 자동으로 선택합니다.
흔히 사용하시는 맥북의 레티나 디스플레이는 더 큰 이미지를 받게 될 것이고, 모바일은 작은 이미지를 사용하게 됩니다.
사실 이건 소개만 드리고, 제가 잘 안써서 정확히는 모릅니다. GPT에 문의하세요
특정 페이지는 사용자가 모든 페이지를 보지 않는 경우도 많습니다. 특히 쇼핑몰이나 재미없는 포스팅 같은게 그럴 수 있죠.
일반적으로는 이러한 페이지에 진입과 동시에 브라우저가 페이지 구성을 위해 페이지 내의 모든 이미지를 다운로드 하는데요, 이게 꽤 낭비가 될 수 있겠죠?
현대의 브라우저는 꽤나 똑똑한데요, 이런 상황을 위해 간단하지만 훌륭한 기능을 제공합니다.
<img src="iamge.jpg" loading="lazy" width="1200px" height="800px">
이처럼 loading="lazy" 하나의 속성 추가로, 우리가 원하던 아래와 같은 기능을 얻을 수 있습니다.
다만 역시나 만능은 아니고, 사용상에 몇가지 주의사항도 있습니다.
LCP(Largest Contentful Paint)가 박살 날 수 있습니다.뷰포트 확인 -> 노출여부 계산 -> 다운로드 요청으로 어렵게 돌아가게 됩니다.loading="eager" + fetchpriority="high", 혹은 rel="preload"로 가져오세요.CLS(Cumulative Layout Shift)를 초래할 수 있습니다. 꼭 요소의 크기를 명시해 주세요.이미지 최적화에 대해 검색하거나, 대화하다 보면 종종 14kb라는 숫자를 종종 만나게 됩니다.
이는 과거 TCP의 초기 혼잡 윈도우(Initial Congestion Window) 크기에서 유래한 기준인데요, 이게 또 나름 재밌습니다.
느린 시작 알고리즘으로 인해 속도가 제한됨이미지 최적화는 웹 개발자에게 꼭 필요한 기술 중 하나입니다. 앞으로 웹 상에서 이미지는 점점 많아질 것이고, 우리는 이를 더 많이 다뤄야 하겠죠.
하지만 이미지 최적화는 그렇게 어려운 일은 아닙니다. 명확한 답이 있지도 않구요.
제가 제시한 기준들이 마음에 들지 않으시다면, 다른 기준을 찾아보셔도 좋습니다.
다른 분들이 이미지를 다루시는데에 조금이나마 보탬이 되면 좋겠네요!
한편으론 요샌 뭐 인터넷 다 빠르니까 좀 욕심을 부려보는게 아닐까 ㅋㅋ 뭐 60hz와 120hz를 구분하시는 분들도 계시니까 ㅋㅋㅋ