최근 최적화에 대한 책을 읽었다.
라고 하는 책인데 읽고나서 그리고 관련된 내용을 실습하고 느낀 생각은
이미지 최적화가 웹앱의 사용자 경험에 지대한 영향을 미친다.
였다.
실제 예전에 했던 프로젝트에서도 .jpg로 된 이미지를 base64로 인코딩해서 http 통신으로 서버에서 프론트로 전달 되도록 한 적이 있었는데 인코딩을 해도 용량이 있다보니 앱을 굉장히 무겁게 만들었던 적이 있다.
해당 프로젝트에서는 인코딩한 데이터를 보내지 않고 클라우드에 업로드된 이미지의 주소를 보내는 식으로 개선했었다.
이번 최적화 책을 통해 그리고 관련 내용들을 찾아보며 알게 된 이미지 최적화에 대한 내용을 img 태그에 관해서만 우선 정리하고자 한다.
단순히 image를 띄우기 위해 사용한 img 태그에는 알지 못하지만 img 좀 더 부드럽게 그리고 최적화해서 화면에 보여주기 위한 여러장치들이 있다.
이미지를 하나의 크기로만 로드 되도록 하는게 아니라 다양한 화면 크기에 맞는 이미지를 로드하도록 하는 방법이다.
모바일, 테블릿, 노트북, 데스크톱 과 같은 기기 크기별로 사이즈에 맞는 이미지를 로드하거나 다른 이미지가 보이게 할 수 있다.
<img
src="기본이 되는 이미지 주소"
sizes="(max-width: 600px) 480px, 800px"
srcset= `${뒤에 오는 사이즈 값에 보여줄 이미지 주소} ${사이즈}`
//예시 "elva-fairy-480w.jpg 480w, elva-fairy-800w.jpg 800w"
/>
// https://developer.mozilla.org/ko/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images
위 예시처럼 srcset에는 각 화면 width 분기에 따라 어떤 이미지를 보여줄지를 정할 수 있다.
위 예시로 보자면 480w 에는 elva-fairy-480w.jpg를 보여주고 800w에는 elva-fairy-800w 이미지를 보여주겠다는 의미가 된다.
분기를 엄청 세세하게 나눈다면 다음처럼 할 수도 있다.
<img
style="width: 100%; border-radius: 1rem;"
src="https://placehold.co/3200x800/png"
srcset="
https://placehold.co/400x100/png 400w,
https://placehold.co/800x200/png 800w,
https://placehold.co/1200x300/png 1200w,
https://placehold.co/1600x400/png 1600w,
https://placehold.co/3200x800/png 3200w
"
sizes="(max-width: 800px) 100vw, 800px"
/>
// https://blog.webdevsimplified.com/2023-05/responsive-images/
작은 크기의 화면에 굳이 고화질의 이미지를 보여줄 필요가 없기 때문에 해당 크기에 맞는 이미지를 보여주는 것이 더 이미지를 빨리 로드하게 해서 UX를 좋게 만든다.
위 srcset 값들은 width 에 대해서만 반응형으로 적응하도록 도와준다. 하지만 만약 같은 width에서 고화질의 이미지를 보여줄 수 있는 기기가 있다면 어떻게 할까?
srcset에 이미지 주소 뒤에 w 로 width 값을 쓰지 않고 x를 사용하면 x값에 따라 더 고화질의 이미지를 보여줄 수 있다.
<img
srcset="elva-fairy-320w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-640w.jpg 2x"
src="elva-fairy-640w.jpg"
alt="요정 옷을 입은 엘바" />
더 고화질의 이미지를 로드 할 수 있다면 더 큰 width 에서 사용할 이미지를 사용하게 할 수도 있다.
요즘 기기 디스플레이에 사용되는 레티나 디스플레이는 인간의 눈보다 더 고화질로 이미지를 보여줄 수 있게 해주기 때문에 2배 정도 사이즈를 넣으면 정 사이즈 이미지보다 선명한 이미지를 볼 수 있다고한다.
이런 최신기기에 대응하기 위한 방법이라 할 수 있겠다.
앞선 내용의 예시들에 보면 sizes 값을 볼 수 있다. (바로 위 말고 그 위에 예시)
sizes 값은 css의 미디어 쿼리를 사용해서 특정 사이즈의 분기에 이미지가 차지하는 크기를 어떤 걸 쓸지를 정하게 해준다.
sizes="(max-width: 800px) 100vw, 800px"
의 경우를 보겠다.
이처럼 값을 정의하면
800px 사이즈가 될 때까지는 이미지를 100vw 사이즈로 보이게 하고 그 이상에서는 800px 사이즈로 보이게 하겠다는 의미이다.
예컨데 위 예시의 디자인에서는 전체 컨텐츠가 width가 아무리커져도 800px까지만 공간을 차지하는 디자인이라서
800px 전까지는 이미지가 전체 width를 다 차지하고 800px를 넘어가면 다른 컨텐츠들처럼 800px를 넘어가지 않게하기 위한 설정이라본다.
은 sizes 값은 작성한 순서대로 인식을 한다는 점이다.
무슨 말이야면
500px 사이즈에 대응하는 이미지 크기를 800px에 대한 값 이후에 작성을 하게되면 원하던대로 작동을 안 할 수 있다는 것이다.
예) 아래 예시는 예상대로 작동하지 않을 수 있다.
sizes="(max-width: 800px) 100vw,(max-width: 500px) 50vw , 800px"
<img src="" alt="" loading="lazy" />
위처럼 설정을 해두면 img 태그가 알아서 웹 브라우져의 스크롤 이벤트에 반응해 이미지가 보이기 전에는 다운로드 되지않고 있다가 스크롤이 올라가 이미지가 보이게 될 시점이 되면 다운로드를 하는 lazy-loading을 할 수 있게 해준다.
설정을 하지 않으면 default 값인 eager로 지정되면 이는 기존처럼 이미지를 스크롤과 관계없이 받아오는 방식이다.
반응형으로 이미지를 사용할 때 화면 크기가 달라짐에 따라 기존의 이미지 사이즈가 맞지 않아서 이미지에서 중요하게 보여져야할 부분이 잘 안보이게 되는 경우가 있다.
MDN에 예시를 보면 중앙에 아기를 안고있는 남자의 사진이 예시로 나온다.
화면의 크기를 줄여보면 이미지가 전체적으로 작아지면서 아기를 안고있는 남자또한 작아지는 것을 볼 수 있다.
데스크톱이나 노트북까지는 그런대로 괜찮지만 핸드폰으로 보게되면 남자와 아기가 매우 작게 보여서 감동적인 장면? 이 잘 안보일 수 있다.
이럴때 사용할 수 있는 태그가 picture 태그이다.
<picture>
<source media="(max-width: 799px)" srcset="elva-480w-close-portrait.jpg" />
<source media="(min-width: 800px)" srcset="elva-800w.jpg" />
<img src="elva-800w.jpg" alt="딸 엘바를 안고 서 있는 크리스" />
</picture>
picture 태그에서는 필수적으로 img 태그가 들어간다.
여기서 사용된 img 태그가 기본 값으로 화면에 보여진다고 생각하면 된다.
source 태그에서는 media 값을 지정하고 해당 값에서는 어떤 이미지를 보여줄 지를 srcset에 지정한다.
여기서의 srcset은 img에서의 srcset과 기능이 동일하기 때문에 저 안에서 다른 이미지로 분기를 나눌수도 있다. 그치잠 source는 위처럼 사용이 가능하기에 굳이 srceset에 여러 url을 넣을 필요는 없다.
위 예시면 보면 이 둘의 차이를 구분하기 힘들다.
img 태그에서 srcset 과 size를 지정하면 똑같이 화면크기에 따라서 다른 이미지를 로드할 수 있는데 굳이 picture가 있는 이유가 왜일까?
그럼 img는 안그렇다는 건가?
그렇다. img 태그에서 사용한 예시를 만들어보면 알 수 있다. 큰 화면에서 img 태그의 srcset과 size로 이미지를 로드하면 화면이 작아져도 해당 이미지를 그대로 사용한다.
작은 화면에서 커지면 새로 이미지를 로드하지만 큰화면에서는 그렇지 않다.
이미지 로드를 최적화하기 위한 방식인데 이미 큰 사이즈, 고화질의 이미지를 다운 받았다면 굳이 작은 이미지를 또 로드할 필요가 없는 것이다.
하지만 picture에 source를 사용하면 미디어 값으로 지정한 분기가 되면 무조건 이미지를 변환한다.
고로 앞서 말한 경우(화면 크기에 따라 계속 이미지를 변환해야하는 경우)에는 picture가 적합하겠다.
css를 사용하면 위 picture의 경우와 비슷하게 구현이 가능하다.
img {
object-fit: cover;
object-position: center;
}
/* https://blog.webdevsimplified.com/2023-05/responsive-images/ */
이미지가 비율을 유지하고 이미지의 가운데가 항상 화면에 가운데가 되도록 하면 위 picture의 아기를 안고있는 남자의 이미지와 비슷한 효과를 줄 수 있다.
하지만 이는 작은 사이즈의 이미지를 로드하면 로드하는 용량을 줄일 수 있다는 picture의 장점을 가지지 못한다.
화면 크기가 크던 작던 고화질의 큰 이미지를 다운받아야 한다는 것이다. picture는 화면이 작은 상태로 계속 있다면 고화질 큰 이미지
를 다운받지 않는다.
이미지를 최적화할 수 있는 방법이 정말 많은 것 같다.
다음에는 html tag 말고 js로 최적화 하는 방법을 다뤄보도록 하겠다.
당장에 다음 글로 할지는 글쎄....
참고
MDN -https://developer.mozilla.org/ko/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images
Web Dev Simplified - https://blog.webdevsimplified.com/2023-05/responsive-images/