상세 컨텐츠

본문 제목

SVG의 불편한 진실

Study/Web

by 2 Mir 2023. 1. 10. 17:28

본문

SVG란?

SVG는 Scalable Vector Graphics의 약자로, 2차원 벡터 그래픽을 서술하는 XML 기반의 마크업 언어라고 MDN에서 정의하고 있다. 우리는 수학 시간에 원점을 지나는 우상향의 대각선에 대해서 좌표평면 위에 그래프를 그릴 수도 있고, y = x 라는 으로 정의할 수도 있다. 간단히 비유해서 전자가 기존의 비트맵 이미지 표현 방식이고, 후자가 SVG 방식이라고 할 수 있다. (x, y)어떤 색깔이 들어가는 지를 정의하는 것이 아닌, 점들 사이의 관계를 정의하는 것이기 때문에 확대해도 깨지지 않고, 파일의 크기가 상대적으로 작다는 장점이 있다.

 

어떻게 쓰는 건데?

<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
  <ellipse cx="100" cy="50" rx="100" ry="50" />
</svg>

 

이는 MDN에 있는 타원을 만드는 SVG 예제로, XML 기반의 마크업 언어라고 했던 만큼 HTML과 상당히 유사한 모습을 보인다.

이 텍스트를 ellipse.svg로 저장한 후 React든 Next든 HTML이든 상관없이 각각의 이미지를 불러오는 방식으로 사용하면 기존 PNG나 JPEG와 똑같이 사용할 수 있다.

 

프로토타입이 피그마로 제작되었다면 아래와 같이 이미지를 바로 SVG로 변환할 수 있기 때문에 조금 더 편리하게 사용할 수 있다.

 

 

그리고 SVG는 라이브러리가 따로 있을 만큼 애니메이션에도 많이 사용하는데, 이 글에서 다루고자 하는 부분도 아니고 자세한 내용은 MDN에 잘 나와있기 때문에 따로 언급하지는 않겠다.

 

치명적인 문제

 

 

소프트웨어 공학 프로젝트를 하던 도중 마주친 문제로, 시작은 단순한 생각이었다. Glassmorphism을 구현하는 데 있어서 위와 같은 그라데이션으로 이루어진 배경이 필요했고, 이를 PNG 파일로 사용하면 600KB인데 SVG로 바꾸면 4KB로 줄어드는 것이다.

 

따라서 디자인 요소의 로딩은 웹에서 UX에 상당히 영향을 줄 수 있다고 생각하기 때문에 SVG로 배경을 적용해 보았다.

 

 

예시로 든 페이지는 아래로 스크롤할 수 있을 만큼 내용이 밑으로 늘어져있는 페이지이다. 보다시피 이 페이지에도 스크롤 영역만큼의 배경 이미지가 필요하다.

 

실제로 맥북의 테스트 환경에서는 버벅거림을 찾아볼 수 없었으나, 배포한 주소에 모바일 기기로 직접 접속해 테스트했을 때 상당한 버벅거림이 있었다. 이 원인에 대해서 당시에는 감으로 SVG가 문제라고 생각해서 해결했으나, 나중에 문제에 대해 자세히 분석해보고자 했다.

 

스크롤 입력에 따른 Performance 비교 (좌: PNG / 우: SVG)

Chrome의 개발자 도구에서 성능을 간단하게 볼 수 있는 Performance Insights 탭에서 위아래로 스크롤하는 행동을 Record 해보았다. 손으로 직접 스크롤하다 보니 완벽한 테스트는 아니었지만, 위와 같이 재밌는 결과가 나왔다. 스크롤할 때 SVG에서만 초록색 영역이 생긴 것이다. 해당 영역은 Composite Layer가 일을 한다는 것을 의미한다.

 

Composite Layer라는 용어가 생소해 좀 더 자세히 찾아보니까 브라우저 렌더링 과정이 주먹구구식으로 외웠던 파싱 후 DOM 만들어서 페인팅하는 게 끝이 아니었다는 사실을 알게 되었다. 기존에 알고 있던 과정은 Main Thread에서 동작하는 과정이고, 렌더링하는 프로세스에는 추가적으로 Compositor ThreadRaster Thread가 존재했다. 이 추가된 Thread에서 하는 일을 한 단어로 요약하면 최적화로, 웹 요소들을 Layer로 분리해서 페이지를 다시 그리는 과정을 최소화하겠다는 것이다. 이렇게 분리한 Layer를 잘 합성하기만 하면 Main Thread에서 진행했던 Layout이나 Paint 과정 없이 화면을 업데이트할 수 있는데, 이 합성이 일어나는 곳이 Composite Layer고, 합성을 하는 주체가 Compositor Thread다. 브라우저 렌더링에 대해서는 다음에 자세히 정리해보기로 했다.

 

추측

여기서부터는 증명된 사실이 아닌, 필자의 추측이 조금 섞인 글이니 주의!

 

Composite와 SVG의 관계에 대해서 계속 다루자면 우리는 Compositor Thread가 하는 일 중 Tiling이라는 과정에 주목해볼 필요가 있다. 이는 페이지 전체를 조각내는 과정인데, 핵심은 그 조각들 중 Viewport에 보이는 조각들을 우선으로 렌더링을 한다는 것이다. 그렇다면 브라우저가 SVG를 어떻게 그리길래 Composite Layer에서 작업이 일어나는지에 대한 의문만 해결하면 되는데, 이를 찾지 못했다.

 

Chrome의 옛 렌더링 엔진이면서 Safari의 렌더링 엔진인 Webkit의 공식 문서를 열어봤는데 "우리는 SVG를 성공적으로 도입했다" 라든지 "SVG 렌더링 성능을 높였다!" 라는 식의 이야기만 있지 그 과정을 언급하지는 않았다. 오픈소스라 코드를 열어볼 수 있었는데, SVG도 캐싱을 해준다는 것 정도만 알아낼 수 있었고 그 외에는 어떻게 동작하는지까지는 이해하지 못했다.

 

캐싱을 지원한다면, 스크롤 동작을 했을 때 최초 한 번만 버벅거리고 그 이후에는 버벅거림이 없어야 하는데 그렇지 않은 것으로 보아 캐싱을 한다고 해서 PNG를 캐싱한 것과 똑같이 동작한다고 볼 수도 없는 것 같다.

 

렌더링 속도 차이 (좌: PNG / 우: SVG)

더 알아볼 수 없다는 사실에 실망하려던 찰나, 렌더링 속도를 다시 비교해 보았다. 이렇게 분석해보니까 좌측에 위치한 실제 페이지에 보이는 애니메이션 속도가 차이가 많이 나고, GIF라서 잘 느껴지지는 않으나 우측에 위치한 레이어 분석 화면에서 배경이 깜빡이는 속도가 PNG일 때 훨씬 빨랐다. 즉, PNG일 때 더 빨리 다시 그린다는 뜻이었다. 사실 텍스트에만 애니메이션을 걸어놓은 거라서 배경은 다시 그려지면 안 될 것 같은데 아무튼 이런 식으로 비교해 볼 수 있었다.

 

따라서 나의 추측은 다음과 같다.

  • 브라우저는 Viewport 영역을 우선으로 렌더링하기 때문에 스크롤 시 변하는 Viewport에 따라 그때그때 다시 그려야 한다.
  • 그리는 속도는 SVG보다 PNG가 훨씬 빠르다.

2번은 사실 당연하다고 볼 수 있는 게, 그래프를 보여주고 똑같이 그리는 것과 함수를 주고 그리는 것의 속도를 비교하면 후자가 훨씬 느릴 수밖에 없다. y = x 라면 속도가 비슷할 수도 있겠지만, 함수가 고차함수나 삼각함수 등으로 복잡하면 복잡할수록 더 느릴 것이다.

 

추가적으로 알게 된 사실로 Composite Layer에서 일어나는 작업은 GPU를 사용한다는 내용이 있었다. 그렇다면 개발 환경(Desktop, Macbook)과 실제 사용 환경(모바일 기기) 사이의 성능 차이도 무시할 수는 없을 것 같다.

 

결론

사실은 자료를 찾기 전부터 추측이 가능했던 결론이어서 Composite Layer 관련 뒷받침할 자료를 찾고 싶었는데, 더 찾지 못해 아쉬웠다.

어쨌든 길게 돌고 돌아 세 줄 요약하면 이렇다.

  • SVG는 PNG보다 훨씬 용량이 작으면서 선명한 이미지를 보여줄 수 있다.
  • 브라우저가 화면에 그리는 속도는 SVG가 PNG보다 느리다.
  • 속도 차이는 성능이 상대적으로 좋지 않은 모바일 환경에서 명백하게 드러난다.

따라서 SVG는 아이콘과 같은 간단한 이미지에 적합하며, 복잡해질 경우 SVG 자체를 최적화하는 방법을 사용하거나 PNG로 대체하는 방법을 고려해볼 수 있겠다는 결론으로 글을 마친다.

 

참고자료

관련글 더보기

댓글 영역