개발을 하다보면 위와 같이 다양한 이미지 형식을 마주하게 되는데요! 그 중에서도 SVG는 특이한 점들이 있습니다. SVG는 왜 이미지 프로그램으로는 열리지 않고 크롬과 같은 웹 브라우저로 열어야 보이는지? 그리고 <svg>
태그로만 구성되지 않고 안쪽에 또 다른 태그들이 왜 있는지?
그래서 이번 글에서는 이렇게 특이한(?) SVG 형식에 대해 알아보려고 합니다 :)
일반적인 이미지(JPG, GIF, PNG 등)은 래스터(Raster) 형식으로 되어 있습니다. 각 픽셀에 색을 포함한 형태의 데이터가 저장되는 형태입니다. 즉, 작은 점을 무수히 여러 번 찍어 만들어낸 이미지를 가리킵니다.
선과 면을 채우는 대신 점을 사용하는 이유는 적은 물감으로 최대한 완성도 높은 이미지를 표현하기 위함이라고 합니다.
따라서 래스터 형식의 이미지를 확대할 경우, 픽셀이 눈에 보일만큼 이미지 품질이 저하되어 보이게 됩니다. 또한, 축소를 하거나 회전 등의 이미지 변형 작업을 할 경우, 안티앨리어싱 과정이 반복되면서 품질 저하가 일어나기 때문에 원본을 완벽하게 유지할 수 없게 됩니다.
📌 안티앨리어싱 과정
앨리어싱(Aliasing)은 디지털 처리 과정에서 발생하게 되는 노이즈를 말하는 용어
다시 말해, 안티앨리어싱은 그래픽 노이즈를 방지하는 기술
즉, 위 사진에 보았던 우둘투둘한 경계의 그래픽을 약간 뭉개는 방법으로 처리하여 매끄럽게 만드는 기술
확대했을 때 이미지가 깨지는 것을 확인할 수 있습니다.
이와 다르게 벡터 형식은 점, 선, 면의 형태로 데이터가 저장됩니다. 점(Anchor)을 이용하면 직선과 곡선, 그리고 면까지 모두 만들어낼 수 있습니다. Figma와 같은 도구에서 펜 툴이 바로 이 원리를 사용하는 것입니다. 이러한 데이터를 가지고 위치나 형태를 수학적으로 계산하여 렌더하는 형식입니다. SVG는 벡터 형식을 가집니다.
그래서 벡터 형식인 SVG는 확대/축소하거나 변경해도 수학적으로 점, 선, 면이 계산되기 때문에 흔히 말하는 "이미지 깨짐 현상"이 없으며, 수정도 훨씬 용이합니다.
벡터 형식의 경우 확대를 해도 화질 저하가 없었습니다.
그래서 기기의 성능을 많이 요구하지 않은 덕분에 래스터 형식의 이미지가 그동안 많이 사용되어 왔던 것입니다. 하지만 지금은 컴퓨터 성능이 많이 좋아져 렌더 과정에 큰 무리가 없으며, 텍스트 형태의 코드로 되어 있는 SVG가 래스터 형식의 이미지보다 훨씬 작은 파일 크기를 가진다는 장점이 있습니다.
하지만 카메라로 찍은 사진과 같이 복잡한 형태의 이미지일 경우, 벡터 형식이라면 연산 과정을 훨씬 더 복잡하며 시간도 오래 걸릴 수 있기 때문에, 이때는 래스터 형식이 더 좋습니다.
SVG 파일은 이미지 프로그램이 아닌 브라우저에서 열리는 이유는 SVG의 내부 형식과 특성 때문인데요!
SVG는 XML 문서로 작성되어 있습니다. XML은 데이터 계층 구조로 나타내기 위한 마크업 언어(ex. HTML, XML, SVG, ...)입니다.
브라우저에서는 SVG 형식의 그래픽을 해석하고 화면에 표시하는 데 사용되는 계산을 수행할 수 있습니다.
반면 이미지 프로그램은 주로 래스터 이미지를 처리하고 편집하기 위한 용도로 되어 있어 브라우저를 통해 SVG를 확인하는 것이 일반적입니다.
틀린 말은 아니지만, PNG가 깨지는 문제를 해결하기 위해 PNG에 더 많은 데이터를 추가하여서 축소 시에도 선명하게 만들 수는 있지만 그러면 웹 성능에 치명적일 수 있습니다.
고해상도의 PNG는 일반적으로 크기가 매우 큽니다. 그렇기 때문에 용량이 큰 PNG를 로드하는 것 자체의 시간이 오래 걸리기 때문에 브라우저의 로딩 속도에 문제가 생길 수 있습니다.
반면 SVG는 코드로 이루어져 있기 때문에 바이트도 안 되는 크기로 이루어져 있어 PNG나 JPG의 이미지보다 용량적인 측면에서 훨씬 적어 웹사이트의 로딩 속도를 훨씬 빠르게 만들어줍니다.
<svg>
태그는 svg 그 자체라기보다 SVG 그래픽을 담기 위한 박스📦라고 생각해야 합니다. svg 태그 내부에 담을 수 있는 것은 원, 사각형, 다각형, 라인, path 등이 있습니다.
내부에 그래픽을 담는 이유는 위에서 말한 것처럼, 수학적 계산을 위한 경로를 사용하여 도형을 그려야하기 때문입니다.
<svg width="가로영역" height="세로영역">
SVG 그래픽...
</svg>
svg 태그 안에 들어가는 태그 중 path 태그도 존재하는데요! 이는 선과 면을 이용한 태그로 여러 속성이 존재합니다.
데이터 종류 | 설명 |
---|---|
M | 이동자표 |
L | 선길이 |
H | 수평선 |
V | 수직선 |
C | 곡선 |
S | 부드러운 곡선 |
Q | 2차 베지어 곡선 |
T | 부드러운 2차 베지어 곡선 |
A | 타원형 호 |
Z | 가까운 경로 |
따라서 아래와 SVG를 만들면 그 다음 형태와 같습니다.
<svg width="400" height="210" >
<path d="M150 0 L75 200 L225 200 Z" />
</svg>
결론적으로, 아이콘과 로고 같은 작은 크기의 이미지는 다양한 크기와 스타일을 유지하면서 품질을 유지하기 위해 주로 SVG를 사용하며, 일반 이미지의 경우 오히려 SVG를 사용할 경우 계산 과정이 훨씬 복잡해져 래스터 형식인 PNG나 JPG를 사용하는 것이 보편적입니다.
생각을 해보니 저도 여러 방법으로 svg를 사용하고 있었던 것 같습니다. 인터넷에서 svg 이미지 링크를 복사한 경우 <img src="" />
방법을 사용했던 것 같고, 라이브러리를 통해 아이콘을 사용하는 경우에는 <svg>
를 사용했던 것 같습니다.
이렇게 svg를 사용하는 방법에는 여러 가지가 있을 수 있는데, 이들에는 어떤 성능 차이가 존재할까요?
아래는 svg 사용 방법에 따른 성능을 비교한 포스팅입니다. 이를 바탕으로 정리를 해보려고 합니다 :)
Which SVG technique performs best for way too many icons?
많은 양의 svg 아이콘 성능에 중점을 둡니다.
한번에 표시되는 아이콘이 100개 미만인 경우 svg 렌더링 최적화에 너무 많은 노력을 기울일 만큼의 크기를 가지지는 않습니다.
아래는 렌더링하는 여러 방법으로 1,000개의 아이콘을 렌더링하는 데 걸린 평균(밀리초) 시간입니다.
<svg viewBox="0 0 24 24" width="24" height="24">
<!-- paths, shapes, etc. -->
</svg>
HTML svg 태그 그대로 사용했을 경우입니다.
최적화된 아이콘의 경우, inline SVG가 성능이 가장 우수했습니다. 반면 최적화되지 않은 경우에는 가장 느립니다.
여기서 '최적화된 svg'라는 것은 중복되고 쓸모없는 정보를 제거하고 지오메트리 경로를 단순화하여 크기를 줄이고 깔끔하게 만드는 것을 의미한다고 합니다.
뿐만 아니라 성능 향상을 위한 svgo라는 최적화 도구도 소개되고 있습니다.
<svg style="display:none">
<symbol id="example" viewBox="0 0 24 24" width="24" height="24">
<!-- paths, shapes, etc. -->
</symbol>
</svg>
<svg><use href="#example"/></svg>
svg를 표현하는 symbol 태그를 만들고, 개별 아이콘은 해당 symbol을 참조하여 표시됩니다. 이 방법의 성능은 렌더링하는 엘리먼트의 개수에 따라 영향을 받습니다.
<img src="path/to/icon/color.svg" alt="">
일반적으로 많이 사용하는 방법인데, inline svg과 비슷하게 img 태그도 성능면에서 좋은 결과를 보였습니다.
조금 눈여겨 볼 점으로는, img 태그를 사용하여 svg를 사용하면 inline svg와 약간의 차이가 발생합니다. 아래 이미지를 보면, 위가 inline svg로 표현한 이미지이고, 아래가 img 태그를 사용한 경우입니다. 이미지 간격이 미세하게 다른 것을 알 수 있습니다.
위와 같이 다른 간격을 가지는 이유에는 여러 가지가 있을 수 있지만, svg 파일 내에 뷰포트(viewport) 설정이나 CSS 스타일링 등이 설정되어 있는데 img 태그를 사용할 경우 해당 설정을 무시하고 이미지를 처리하므로 크기와 위치가 달라질 수 있습니다.
<img src="data:image/svg+xml,..." alt="">
svg 파일은 마크업 텍스트로 되어 있기 때문에, base64 인코딩 없이 data URI 스트링 형태로 쉽게 변환이 가능합니다. 해당 방법이 최적화/최적화 되지 않은 svg 모든 경우에서 성능이 가장 우수했습니다.
📌 data URI
이미지 등의 외부 바이너리 파일을 웹페이지에 인라인으로 넣기 위해 사용
외부 데이터를 별도의 파일로 두지 않고 HTML 파일로 관리할 수 있다.
request 수를 줄여 빠른 전송효과를 볼 수 있다.
<div style="background-image: url(path/to/icon/color.svg);">...</div>
백그라운드 이미지는 img 태그나 inline svg보다는 성능이 떨어졌습니다.
<div style="
-webkit-mask-image: url(path/to/icon.svg);
mask-image: url(path/to/icon.svg);">
...
</div>
CSS mask 속성은 아이템이 부분적으로만 보여지게 하거나 혹은 완전히 가려서 보여지지 않게 할 수 있는 기능입니다. mask-image 속성을 사용하면 요소의 마스크 레이어로 사용되는 이미지를 설정할 수 있습니다. 저는 사용해본 적이 없는 방법인데, 이렇게도 이미지를 표현할 수 있구나하고 알게 되었던 것 같습니다. 성능은 그닥 좋지는 않았습니다.
결론
svg 태그를 사용하는 방법과 uri를 사용하는 방법 그리고 img 태그를 사용하는 방법이 성능면에서 가장 우수했습니다.
반면, 흔히 사용될 수 있는 background-image는 성능면에서 좋은 편에 속하지는 못하다는 것도 알 수 있었습니다.
작은 크기의 이미지(흔히 아이콘이나 로고)에서는 품질 저하 없이 크기 조절 및 스타일링이 가능한 svg를 사용하는 것이 적합합니다. 반면, 일반 이미지의 경우 svg는 계산을 요하기 때문에 오히려 이미 렌더되어 있는 래스터 형식의 PNG나 JPG가 더 적합합니다.
성능 면에서는 svg 태그를 사용하는 방법, img 태그를 사용하는 방법, uri를 사용하는 방법이 가장 우수했습니다.