logo
Published on

[프론트엔드 성능 최적화]미디어 최적화

Authors
  • avatar
    Name
    Kevin(서희원)
    Twitter

프론트엔드 입장에서 웹의 화면을 보자면.. 보통 영역을 어떻게 설정해야하는가 외에도 사진, 동영상, 폰트 등 미디어들은 필수적으로 다루게 됩니다. 특히 브라우저에서 일반적인 사이트를 불러오는데 전체의 50%가 이미지이고, 25%가 비디오로 가져온다는 통계도 존재할 만큼, 프론트엔드에서 가장 먼저 효과적으로 최적화할 수 있는 영역입니다.

그렇다면 이런 미디어들을 어떻게 다루어야 가장 최적으로 화면에 빠르게 보여줄 수 있을까요? 이번엔 미디어 자체와 미디어를 다루는 것에 대해 이야기를 해보고자 합니다.

참고로 지연로딩이나 사전로딩과 관련한 내용은 이 페이지로 들어가시면 됩니다.

(오른쪽이 안보이는 사람들을 위한)목차

이미지         이미지 사이즈         이미지 api         이미지 포맷

동영상         동영상 압축         동영상 화질 저하 보완법

폰트         폰트 나중에 보여주기         폰트 용량 줄이기

마무리

레퍼런스

이미지

위에서도 언급했지만, 이미지는 가장 많은 데이터를 차지할만큼, 너무 무거운 이미지를 활용하여 사이트를 만든다면 성능이 저하될 수 밖에 없습니다. 그렇기 때문에 일단 사이즈와 포맷, 그리고 링크의 측면에서 살펴보겠습니다.

이미지 사이즈

Chrome의 lighthouse와 같은 측정도구로 웹 사이트의 성능을 측정하다보면 Opportunities 섹션에서 이런 문구를 볼 수 있습니다.

Properly size images

이 문구는 이미지를 적절한 사이즈로 사용하라는 제안이므로, 렌더링되는 이미지의 크기보다 너무 큰 용량의 이미지를 사용하게 된다면 단순히 로딩 속도가 더 길어집니다.

그러므로 이 이미지의 가장 적절한 크기가 어느정도인가? 찾고자 한다면 다음과 같은 순서로 이미지를 찾아보면 됩니다.

  1. 크롬 개발자도구(f12)를 킨다.
  2. Elements(요소)탭에 들어간다.
  3. 개발자도구 맨 왼쪽 위에 아래 사진과 같은 아이콘을 클릭하거나 사이트의 특정 이미지를 우클릭 → 검사를 클릭하여 Elements의 안에 지정한 영역을 강조해준다.

  1. 해당 태그의 src속성을 hover하면 아래 사진처럼 정보를 볼 수 있습니다.

일단 위에서는 거의 적절한 크기의 이미지를 제공하고 있지만, 만약 렌더링된 크기보다 너무 큰 고유 크기를 가지고 있다면, 고유 크기의 값을 줄여야 사이트 성능 개선에 도움이 됩니다. (참고로 레티나 디스플레이도 고려하여 렌더링된 크기에서 2배정도 늘려 고유 크기를 설정하는 경우도 있지만, 여기서는 다루지 않겠습니다.)

이미지 api

이미지를 로컬에 저장하여 불러오는 경우도 있지만, 위의 사진처럼 api를 통해 불러오는 경우도 있습니다. 이 경우 만약 이미지 소스가 저장된 곳이 해외에 있다면 매우 오랜 시간이 걸릴 것입니다. 하지만 cdn을 활용하여 비교적 가까운 곳에서 이미지를 불러온다면 빠른 시간에 이미지를 불러올 수 있습니다.

사진 출처: https://www.tencentcloud.co.kr/index.php/2021/09/01/document-17/

추가로 일부 cdn 서비스를 제공하는 회사에서는 이미지를 api로 불러올 경우, 변경하고 싶은 사항이 있다면 api url 뒤쪽에 쿼리스트링을 활용하여 아래처럼 입력하여 사용하는 경우도 있습니다.

cdn.image.com?src=[img src]&width=240&height=240

이미지 포맷

이미지에는 포맷들이 여럿 존재하는데요, 대표적으로 jpg, webp, png가 있습니다. 이 셋 중에서 비교해보자면 다음과 같은 성능을 가지고 있습니다.

이미지 호환성이미지 사이즈이미지 화질
png>jpg>webppng>jpg>webppng>webp>jpg

그래서 이 세가지 부분을 고려하여 보면 가장 사용하기 적합한 포맷은 webp인 것을 알 수 있습니다. 하지만 이미 webp 포맷을 사용하지 않는 경우라면 어떻게 해야할까요?

그 방법은 두가지로 볼 수 있습니다.

  1. Squoosh와 같은 포맷 변환 사이트에서 변환하기
  2. sharp 모듈을 통해 변환하기

일단 Squoosh는 사이트에서 쉽게 변환 가능하므로 넘어가고,

sharp 모듈을 통해 변환하는 과정을 살펴보겠습니다.

  1. 터미널에 다음과 같이 입력합니다. npm install sharp
  2. 아래와 같이 코드를 입력하여 이미지의 포맷을 변경합니다.
const sharp = require('sharp')

async function convert(inputPath, outputPath, width, height) {
  try {
    await sharp(inputPath).resize(width, height).toFormat('webp').toFile(outputPath)
  } catch (error) {
    console.log(error)
  }
}

const input_path = 'main-items.jpg' //상대 경로
const out_path = 'main-items.webp' //상대 경로
convert(input_path, out_path, 600, 600)

이렇게 실행 하면 .jpg 외에 .webp 포맷의 이미지 파일이 하나 더 생겨납니다.

동영상

다음으로 비교적 적은 비중을 차지하는 동영상이지만, 1초에 평균적으로 약 60개의 이미지가 보여지는 만큼, 사이트에 재생되는 동영상이 버벅인다면 사용자 입장에서 불편하게 느낄 수 밖에 없습니다. 그래서 동영상을 압축하고, 이로 인한 화질 저하 대처법을 소개하며 최적화를 시도하겠습니다.

참고로 동영상을 주로 서비스하는 사이트에는 별로 추천하지 않습니다.

동영상 압축

동영상 자체의 용량을 줄이기 위해 동영상을 압축하는 방법이 있습니다. 그래서 이미지와 비슷하게 두가지 해결법이 있는데, 다음과 같습니다.

  1. Media.io를 이용하여 온라인으로 비디오를 변환하기
  2. ffmpeg를 다운받아 직접 변환하기

위에서 본 방식과 동일하게 이번에도 ffmpeg를 활용한 변환에 대해 살펴보겠습니다.

  1. https://www.ffmpeg.org/download.html여기서 운영체제에 맞게 다운받습니다.
  2. 아래 코드를 터미널에 입력하여 변환을 시작합니다.
cd (동영상이 있는 폴더 위치)
ffmpeg -i input.mp4 -c:v libvpx -crf 10 -b:v 1000k output.webm

추가로 원래 명령어는 다음과 같습니다.

General Options
-i input.mp4: specifies the input file
-c:v libvpx: specifies the video codec to use (in this case, VP8)
-c:a libvorbis: specifies the audio codec to use (in this case, Vorbis)
-f output.webm: specifies the output file format (in this case, WebM)

Video Options
-crf 10: sets the quality of the video encoding (lower values result in higher quality, but larger files)
-b:v 500k: sets the video bitrate (in this case, 500 kbps)
-s 640x480: sets the resolution of the output video (in this case, 640x480)
-aspect:v 16:9: sets the aspect ratio of the output video (in this case, 16:9)

동영상 화질 저하 보완법

이렇게 해서 동영상의 용량을 획기적으로 줄일 수 있습니다.

하지만 용량이 줄은 만큼 동영상의 화질은 나빠질 수 밖에 없는데요, 이번엔 어떻게 보완하는지 살펴보겠습니다.

  1. 영상을 블러처리하기

    css의 filter: blur(10px)을 해당 영상에 입력하면 영상이 조금 흐려집니다. 그래서 만약 굳이 영상을 또렷이 보여줄 필요가 없다면 이렇게 입력하는 것도 방법입니다.

  2. 필터 씌우기

    특정 패턴이 있는 이미지를 비디오 위에 얹으면 사용자 입장에서 비디오를 낮은 화질인 것으로 인식하는 걸 어느정도 줄일 수 있습니다.

폰트

위와 같이 폰트가 페이지 로딩 중에 바뀌게 된다면 사용자 입장에서 불편할 수 밖에 없습니다. 그래서 이번에는 폰트의 로딩 방식과 어떻게 폰트를 최적화 할 수 있는지 살펴보겠습니다.

위의 사진을 보면 렌더링하는 과정을 볼 수 있는데, 여기서 폰트는 CSSOM이 만들어지면서 다운로드를 요청합니다. 그래서 폰트가 갑자기 바뀌는 현상은 로딩 시점이 비교적 뒤에 있기 때문에 벌어지는 것입니다. 이를 두고 FOIT, FOUT 2가지 현상이 있다고 합니다. 각각 살펴보면 다음과 같습니다.

폰트 나중에 보여주기

  • FOIT(Flash Of Invisible Text)

    브라우저가 웹 글꼴을 다운로드하기 전에 텍스트가 보이지 않는 현상입니다.

  • FOUT(Flash Of Unstyled Text) 브라우저가 웹 글꼴을 다운로드하기 전에 텍스트가 대체 글꼴로 렌더링되는 현상

두가지 현상 모두 이상적이지 않지만, 그래도 Chrome에서는 3초 timeout을 가진 FOIT을 사용하기 때문에 해결해볼 방법으로 CSS의 font-display: block을 사용하여 처음에는 텍스트를 보여주지 않다가 나중에 폰트까지 적용될 경우 폰트가 적용된 텍스트를 보여줍니다.

폰트 용량 줄이기

폰트의 포맷은 보통 https://transfonter.org/에서 .ttf가 아닌 .woff 혹은 .woff2로 변경하여 사용하면 폰트의 용량을 어느정도 줄일 수 있습니다.

여기서 더 줄일 수 있는데, 바로 특정 문자열만 폰트 적용해서 추출하는 방식이 있습니다.

그리고 더 나아가서 base64 encode 속성을 활성화하면 .css 포맷의 파일에 특정 문자열이 있는데, 이 문자열을 복사하여 파일 경로 대신 폰트 url에 넣으면 따로 폰트 파일을 다운받지 않고, css파일에 포함되어 다운 받는 모습을 볼 수 있습니다.

마무리

이렇게 해서 미디어와 관련한 최적화에 대해 이미지, 비디오, 폰트 각각 살펴보았습니다. 이게 얼핏 보면 프론트엔드 개발 영역에서 가장 쉽지만, 간과하기 쉬운 부분이라는 것을 깨닫게 되었고, 나중에 개발을 진행할 경우 고려해야겠다 생각하게 되었습니다. 제 글을 봐주셔서 감사합니다.

레퍼런스