프론트엔드 성능 최적화 - 4. 이미지 파일 최적화

2021. 8. 29. 01:39웹 프론트엔드 깊게 이해하기/성능 최적화

이 글은 아래 링크의 내용을 바탕으로 작성되었습니다.

https://jeonghwan-kim.github.io/series/2020/01/02/frontend-dev-env-webpack-intermediate.html

https://www.youtube.com/watch?v=2QYpkrX2N48

https://developer.mozilla.org/ko/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images

 

어플리케이션에서 이미지가 차지하는 비율은 절반을 넘어가는 일이 많습니다. 그만큼 이미지를 압축하는 일은 이용자가 웹사이트의 컨텐츠를 빨리 받아보기 위해 아주 중요한 일입니다. 이번에도 이미지를 압축할 수 있는 가장 간단하고 유용한 방법을 먼저 선택하도록 하겠습니다.

 

 

이미지 파일 압축 / 형식 변환

 

이미지 용량를 줄이는 가장 확실한 방법은 압축률이 더 높은 이미지 형식으로 파일을 변환하거나, 이미지 해상도를 낮추는 것입니다. 이를 직접 포토샵과 같은 도구를 통해 할 수도 있겠지만, 무료로 이용할 수 있는 이미지 리사이징 툴을 하나 소개해드리겠습니다.

 

https://squoosh.app/

 

Squoosh

Simple Open your image, inspect the differences, then save instantly. Feeling adventurous? Adjust the settings for even smaller files.

squoosh.app

 

이 서비스를 이용하면 원하는 형식과 원하는 해상도로 이미지를 리사이징 할 수 있습니다. 하나의 예시로 이미지 하나를 리사이징 해보겠습니다.

 

 

 

 

이 이미지는 무려 10.1MB 의 크기를 자랑하는 png 파일입니다. 4100 x 2735 라는 말도 안되는 해상도를 자랑하는군요. 서비스 이용자의 기기 너비가 1980 x 1080 을 넘을 일이 많지 않을 것이라 가정하고 저는 이 이미지를 1980px 너비에 맞게 리사이징 해보겠습니다.

 

 

파일 형식을 바꾸지 않고도 압축 + 이미지 리사이징 만으로 10.1MB → 2.63MB 로 74% 의 용량 감소를 이룰 수 있었습니다. 만일 파일 형식 자체를 바꾼다면 어떻게 될까요? 이번엔 리사이징을 적용하면서 동시에 파일 형식 또한 변환해보겠습니다.

 

 

파일 형식을 webp 로 전환하니 무료 10.1MB → 198KB 로 98% 의 용량 감소를 얻을 수 있었습니다. 그러나 이런식으로 함부로 이미지 파일 형식을 변환해도 되는 것일까요? '대부분의 상황에서는 괜찮다' 는 것이 저의 결론이지만 그 근거가 궁금하신 분들은 아래의 글을 참고해보시기 바랍니다.

 

https://codingmoondoll.tistory.com/entry/%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%99%95%EC%9E%A5%EC%9E%90%EB%B3%84-%ED%8A%B9%EC%A7%95-%EC%A0%95%EB%A6%AC

 

이미지 확장자별 특징 정리

이 글은 아래의 링크의 내용을 바탕으로 작성되었습니다. https://www.youtube.com/watch?v=Z_28syzkv-0 최근엔 초월적인 압축률을 자랑하는 webp 이미지 형식이 등장하면서 웹에서 이 형식의 이미지를 활용

codingmoondoll.tistory.com

 

 

image-webpack-loader를 이용한 이미지 압축

위와 같은 외부 서비스를 활용하여 이미지를 리사이징하고 압축하고, 형식을 변환할 수 있지만 단순한 이미지가 아닌 gif 파일을 압축하거나 많은 이미지에 대해서 일괄적인 압축 처리를 하고 싶을 때는 webpack 의 플러그인을 사용하는 것이 가장 간편한 방법입니다. 이에 대해서는 수많은 플러그인들이 존재하지만, 저는 사용법이 가장 간단한 image-webpack-loader 를 활용해서 이를 처리해보겠습니다. 방법은 매우 간단합니다.

 

 

module: {
  rules: [
    {
      test: /\.(png|jpg|jpeg|gif|webp)$/i,
      loader: 'image-webpack-loader',
      enforce: 'pre',
    },
  ]
}

 

위의 규칙을 webpack.config.js 파일 안에 추가시켜주면 됩니다.

 

 

이용자의 기기 환경에 따라 다른 이미지 전송

 

단순히 파일 사이즈를 줄였다고 해서 이미지에 대한 최적화 작업이 모두 끝난 것은 아닙니다. 위의 예시에서 든 hero.png 파일은 해상도가 1980 x 1080 으로, 큰 모니터 화면에 적합한 해상도를 가지고 있습니다. 만일 이용자가 모바일 기기에서 접속했다면 저 정도로 큰 해상도의 이미지를 사용할 필요는 없을 것입니다. 따라서 사용자의 현재 기기 사이즈에 따라 각기 다른 이미지를 웹앱이 사용하도록 설정하는 작업이 필요한 것입니다.

 

방법은 생각보다 단순합니다. img 태그의 srcset 속성을 활용하는 것입니다. 실습을 위해 https://squoosh.app/ 사이트에서 이전의 hero.webp 이미지를 Desktop, Tablet, Mobile 용으로 하나씩 만들어보겠습니다.

 

 

 

위와 같이 설정할 경우, 창의 크기가 768px 보다 높을 경우 heroDesktopImage 가, 375px 보다는 높지만 768px 보다는 낮을 경우 heroTabletImage 가 사용되는 것을 확인할 수 있습니다.

 

 

  • 주의! : srcset 에 사용되는 w 값은 온전히 px 을 의미하는 것이 아닙니다. 만일 사용자의 기기가 애플의 Retina 디스플레이와 같이 고밀도의 화소를 가지고 있다면 브라우저의 1px 은 사실 다른 기기의 1px 보다 큰 영역을 나타낼 수 있습니다. 그렇기에 예를 들어 일반 화소의 3배에 해당하는 고밀도의 화소를 가지고 있는 기기내에서 375w 는 사실 125px 을 의미하게 됩니다.
  • 따라서 '미디어 쿼리'와 같은 개념으로 w 값을 받아들이면 안됩니다. 만일 실제 기기의 너비에 따라 이미지의 CSS 너비를 조정하고 싶다면 sizes 속성을 사용하거나 source 태그의 media 속성을 활용하는 것이 좋습니다.

 

그러나 이것으로 완전히 이미지 최적화 작업이 끝난 것은 아닙니다. 말씀드렸듯이 webp 파일 형식은 구형 브라우저에서는 읽어들일 수 없습니다. 따라서 webp 를 읽을 수 없는 브라우저에서는 대체용 이미지를 대신 보여주는 처리를 해줄 필요가 있습니다.

 

직접 자바스크립트를 통해 이를 처리할 수도 있겠지만 가장 간편한 방법은 HTML 의 <picture></picture> 태그를 사용하는 것입니다.

 

 

이렇게 하면 IE 와 같이 srcset 과 webp 를 지원하지 않는 구형 브라우저에서도 이미지 자체는 보여줄 수 있게 됩니다. source 가 기본으로 보여줄 이미지이며 여러개를 설정할 수 있습니다. source 에 해당하는 이미지 중 보여줄 수 있는 것이 없을 때 마지막에 위치시킨 img 태그가 사용됩니다.