로고나 아이콘, 혹은 기하학적인 배경 무늬를 넣기 위해 SVG를 자주 사용하게 될 텐데요.
SVG(Scalable Vector Graphics)는 픽셀이 아닌 수학적 좌표로 이루어져 있어서 아무리 화면을 늘리거나 줄여도 절대 깨지지 않는다는 엄청난 장점이 있습니다. 하지만 바로 그 '유연함' 때문에 CSS로 배경 크기(background-size)를 조절하려고 할 때 내가 생각한 대로 움직이지 않아서 멘붕(?)에 빠지는 경우가 정말 많습니다.
오늘 우리가 살펴볼 MDN 공식 문서는 바로 이 문제를 명쾌하게 해결해 줄 'SVG 배경 크기 조절하기(Scaling SVG backgrounds)'입니다. 실무에서 정말 밥 먹듯이 마주치게 될 내용이니, 저와 함께 원리를 하나하나 완벽하게 파헤쳐 봅시다!
SVG 이미지의 유연성을 생각해보면, background-image 속성을 이용해 SVG를 배경 이미지로 사용할 때 명심해야 할 것들이 꽤 많습니다. 게다가 background-size 속성을 사용해 크기를 조절할 때는 고려해야 할 점이 훨씬 더 많아지죠. 이 문서에서는 이러한 속성들을 사용할 때 SVG 이미지의 크기 조절이 브라우저 내부에서 어떻게 처리되는지 설명합니다.
배경 이미지의 배경 크기를 결정할 때 사용되는 알고리즘은, 대부분의 경우 다음 4가지 규칙으로 요약할 수 있습니다. 이 규칙들로 설명되지 않는 몇 가지 엣지 케이스(예외적인 상황)가 있긴 하지만, 이 4가지 규칙만으로도 대다수의 상황을 커버할 수 있습니다.
background-size에 고정된 치수(fixed dimension)가 지정되어 있다면 (즉, 퍼센트나 상대 단위가 그 컨텍스트에 의해 고정된 크기를 가질 때), 그 지정된 치수가 최우선으로 적용(wins)됩니다.constrain이나 cover 같은 설정에 의해 변경되지 않았다면, 이미지에 명시된 그 크기가 우선 적용됩니다.여기서 한 가지 짚고 넘어갈 점은, 배경 크기 조절 알고리즘은 오직 이미지의 '치수(dimensions)'와 '비율(proportions)'(혹은 둘 다 없는 경우)에만 신경 쓴다는 것입니다. 고정된 치수를 가진 SVG 이미지는 동일한 크기의 래스터 이미지(PNG, JPG 등)와 똑같이 취급됩니다.
참고:
CSS를 이용해 SVG를 다른 종횡비(aspect ratio)로 잡아 늘리려고 한다면 — 예를 들어 페이지 전체 배경에 꽉 차게 늘리기 위해 — 반드시 여러분의 SVG 코드 안에preserveAspectRatio="none"이 포함되어 있는지 확인하세요.preserveAspectRatio속성에 대해 더 알아보세요.
💡 강사 팁:
이 부분이 핵심입니다! 실무에서 "강사님, SVG 배경이 자꾸 위아래로 빈 공간이 남고 안 늘어나요!"라고 질문하는 분들 열에 아홉은 SVG 태그 안에preserveAspectRatio="none"을 넣지 않아서 그렇습니다. SVG는 기본적으로 자기 자신의 원래 비율을 어떻게든 지키려고 고집을 부리거든요. 이걸 해제해 주어야 CSS로 내 마음대로 찌그러뜨리거나 꽉 채울 수 있습니다.
다양한 종류의 SVG 원본 이미지들을 사용했을 때의 결과를 본격적으로 파헤쳐 보고, background-size를 적용했을 때 어떻게 보이는지 확인하기 전에, 서로 다른 치수와 크기 설정을 가진 몇 가지 예제 원본 이미지들을 미리 살펴두는 것이 좋습니다. 우리는 나중에 이 이미지들을 예제의 background-image 값으로 사용할 것입니다.
참고로 브라우저는 기본적으로 <svg> 이미지를 300px 너비에 150px 높이로 렌더링합니다.
아래의 SVG 그래디언트 이미지는 치수(가로세로 크기)도 없고 고유 비율도 없습니다. 이 이미지는 자신이 어떤 크기가 되어야 하는지 신경 쓰지 않고, 특정 종횡비를 유지하는 것에도 관심이 없습니다. 이런 이미지는 화면 크기나 비율에 상관없이 작동해야 하는 데스크톱 배경화면 같은 용도로 사용하기에 아주 좋습니다.
<svg>
<title>Corner-to-corner gradient</title>
<defs>
<linearGradient id="g" x1="0%" x2="100%" y1="0%" y2="100%">
<stop stop-color="pink" offset="0" />
<stop stop-color="goldenrod" offset="1" />
</linearGradient>
</defs>
<rect fill="url('#g')" width="100%" height="100%" />
</svg>

MDN Playground에서 실행해보기 (Live Sample)
이 이미지는 너비(width)를 100 픽셀로 명시하고 있지만, 높이(height)나 고유 비율은 설정되어 있지 않습니다. 이 이미지는 기본적으로 얇은 벽지 띠와 같아서, 블록 요소의 전체 높이를 따라 위아래로 길게 늘어날 수 있습니다.
<svg width="100">
<title>Vertical gradient, with a fixed width</title>
<defs>
<linearGradient id="g" x1="0%" x2="0%" y1="0%" y2="100%">
<stop stop-color="purple" offset="0" />
<stop stop-color="lime" offset="1" />
</linearGradient>
</defs>
<rect fill="url('#g')" width="100%" height="100%" />
</svg>

MDN Playground에서 실행해보기 (Live Sample)
이 이미지는 높이를 100 픽셀로 명시했지만 너비는 명시하지 않았습니다. 대신 viewBox="0 0 3 4"를 통해 3:4라는 고유 종횡비를 명시하고 있죠. 이렇게 하면 고의로 불균형한 크기로 조절되지 않는 이상 (즉, CSS에서 해당 비율에 맞지 않는 너비와 높이를 강제로 둘 다 지정하지 않는 한) 너비:높이 비율은 항상 3:4로 유지됩니다.
사실 이것은 너비와 높이를 둘 다 명시하는 것과 매우 비슷합니다. 치수 하나와 비율을 알면, 나머지 치수 하나는 자연스럽게 유추할 수 있으니까요.
<svg height="100" viewBox="0 0 3 4" preserveAspectRatio="none">
<title>Vertical gradient, with a fixed height and intrinsic ratio</title>
<defs>
<linearGradient id="g" x1="0%" x2="0%" y1="0%" y2="100%">
<stop stop-color="teal" offset="0" />
<stop stop-color="orange" offset="1" />
</linearGradient>
</defs>
<rect fill="url('#g')" width="100%" height="100%" />
</svg>

MDN Playground에서 실행해보기 (Live Sample)
이 이미지는 너비나 높이를 지정하지 않았습니다. 대신 1:1이라는 고유 비율을 지정했죠(viewBox="0 0 1 1"). 이 이미지는 항상 정사각형 모양을 유지하며, 예를 들어 32x32, 128x128, 512x512 등 어떤 크기에서든 사용할 수 있습니다.
<svg viewBox="0 0 1 1" preserveAspectRatio="none">
<title>Intrinsic ratio</title>
<defs>
<linearGradient id="g" x1="0%" x2="100%" y1="0%" y2="0%">
<stop stop-color="navy" offset="0" />
<stop stop-color="maroon" offset="1" />
</linearGradient>
</defs>
<rect fill="url('#g')" width="100%" height="100%" />
</svg>

1:1 비율이라서 width는 부모의 width만큼 늘어났고 height도 너비만큼 늘어났기 때문에 우측에 스크롤바가 생겼습니다.
MDN Playground에서 실행해보기 (Live Sample)
💡 강사 팁:
방금 살펴본 4가지 SVG 코드를 잘 눈여겨보세요. SVG 태그 안에width,height,viewBox가 어떻게 적혀있느냐에 따라 브라우저가 이 이미지를 다루는 방식이 완전히 달라집니다. 특히 로고 파일 등을 디자이너에게 넘겨받았을 때, 이 속성들을 적절히 튜닝할 줄 알아야 프론트엔드 장인으로 거듭날 수 있습니다!
자, 이제 이 이미지들에 다양한 크기 조절 방식을 적용했을 때 어떤 일이 일어나는지 예제를 통해 확인해 봅시다. 아래의 각 예제에서, 이미지를 감싸고 있는 <div> 요소들은 너비 300 픽셀, 높이 200 픽셀이며, 2픽셀 두께의 테두리(border)를 가지고 있습니다. 이 시연을 위해 SVG 배경 이미지가 한 번만 표시되도록 background-repeat 속성을 no-repeat으로 설정했습니다.
div {
width: 300px;
height: 200px;
background-repeat: no-repeat;
border: 2px solid black;
}
만약 background-size를 사용하여 가로와 세로 두 치수에 모두 고정된 길이를 지정한다면, 앞서 살펴본 1번 규칙에 따라 항상 그 지정된 길이가 적용됩니다. 다시 말해, 원본 SVG 이미지 안에 치수나 종횡비가 어떻게 적혀있든 간에 상관없이 여러분이 CSS에 지정한 크기 그대로 쫙 늘어나거나 찌그러집니다.
이 예제에서는 원본 이미지에 치수나 고유 비율이 전혀 설정되어 있지 않습니다.
<div></div>
div {
background-image: url("no-dimensions-or-ratio.svg");
background-size: 125px 175px;
}

MDN Playground에서 실행해보기 (Live Sample)
이번에는 원본 이미지에 치수가 하나 지정되어 있지만 고유 비율은 없는 경우입니다.
<div></div>
div {
background-image: url("100px-wide-no-height-or-ratio.svg");
background-size: 250px 150px;
}

MDN Playground에서 실행해보기 (Live Sample)
이 예제에서는 원본 이미지에 치수가 1개 설정되어 있고 고유 비율도 명시되어 있어, 사실상 두 치수가 모두 정의된 것과 같습니다. 하지만 CSS의 background-size로 절대적인 높이와 너비를 설정해버리면 SVG에 설정된 치수들은 무시되고 CSS 설정이 우선순위를 갖습니다.
<div></div>
div {
background-image: url("100px-height-3x4-ratio.svg");
background-size: 275px 125px;
}

MDN Playground에서 실행해보기 (Live Sample)
이 예제에서는 원본 이미지에 치수가 1개 설정되어 있고 고유 비율도 명시되어 있어, 사실상 두 치수가 모두 정의된 것과 같습니다. 하지만 CSS의 background-size로 절대적인 높이와 너비를 설정해버리면 SVG에 설정된 치수들은 무시되고 CSS 설정이 우선순위를 갖습니다.
<div></div>
div {
background-image: url("100px-height-3x4-ratio.svg");
background-size: 275px 125px;
}

MDN Playground에서 실행해보기 (Live Sample)
background-size를 cover로 지정하면, 전체 배경 영역을 완전히 덮는 선에서 이미지를 가능한 한 가장 작게 만듭니다 (비율을 유지하며 확대/축소하되 넘치는 부분은 잘림).
반면 contain은 배경 영역 바깥으로 잘려나가는 부분이 없도록 하면서 이미지를 가능한 한 가장 크게 만듭니다 (비율을 유지하며 박스 안에 온전히 다 들어가게 함).
만약 이미지에 고유 비율이 존재한다면, cover나 contain 기준에 딱 맞아떨어지는 완벽한 사이즈가 단 하나 존재하게 됩니다. 하지만 만약 이미지에 고유 비율이 지정되어 있지 않다면 cover와 contain 자체만으로는 계산이 충분하지 않기 때문에, 가장 크게/가장 작게 만들어야 한다는 조건에 따라 결과적인 크기가 결정됩니다.
원본 이미지에 치수나 고유 비율이 설정되어 있지 않은 경우입니다. 이미지가 치수나 고유 비율 중 아무것도 제공하지 않는다면 앞의 2번, 3번 규칙을 적용할 수 없으므로 4번 규칙이 발동합니다. 즉, 배경 이미지는 전체 배경 영역을 꽉 채우도록 렌더링됩니다. 이것은 '가장 크게' 혹은 '가장 작게' 만들어야 한다는 제약 조건을 동시에 만족시키는 결과입니다.
<div></div>
div {
background-image: url("no-dimensions-or-ratio.svg");
background-size: contain;
}

MDN Playground에서 실행해보기 (Live Sample)
이 예제처럼 이미지에 한쪽 치수만 지정되어 있고 고유 비율이 없다면, 역시 4번 규칙이 적용되어 이미지가 전체 배경 영역을 덮을 때까지 스케일링됩니다.
<div></div>
div {
background-image: url("100px-wide-no-height-or-ratio.svg");
background-size: contain;
}

MDN Playground에서 실행해보기 (Live Sample)
이 예제들에서는 원본 이미지에 치수가 1개 명시되어 있고, 고유 비율도 함께 있습니다.
고유 비율이 명시되는 순간 상황이 달라집니다. 이 경우 1번 규칙(CSS 고정값 우선)은 해당하지 않으므로, 2번 규칙이 적용됩니다. 즉, (contain이나 cover 옵션을 존중하는 선에서) 고유 비율을 유지하려고 시도합니다.
예를 들어, 300x200 크기의 박스에 contain 옵션을 주고 3:4 고유 비율을 유지하려 한다면 브라우저는 이미지를 150x200 크기로 렌더링하게 됩니다.
<div></div>
div {
background-image: url("100px-height-3x4-ratio.svg");
background-size: contain;
}

MDN Playground에서 실행해보기 (Live Sample)
잘린 부분 없이 박스 안에 온전히 들어갈 수 있도록 전체 이미지가 가장 알맞은 사이즈로 렌더링 된 것을 확인할 수 있습니다.
<div></div>
div {
background-image: url("100px-height-3x4-ratio.svg");
background-size: cover;
}

MDN Playground에서 실행해보기 (Live Sample)
여기서는 3:4 비율을 유지하면서도 이미지를 쫙 늘려 전체 박스를 가득 덮고 있습니다. 이 때문에 이미지의 아랫부분이 잘려나가는(clipped) 현상이 발생합니다.
만약 SVG에 치수는 없고 고유 비율만 설정되어 있다면, contain이나 cover를 쓸 때 기본적으로 4번 규칙(배경을 채움)이 적용되는 듯하지만, 사실 2번 규칙(비율 유지)도 함께 적용됩니다. 따라서 contain 예제와 똑같은 방식으로 렌더링 됩니다.
<div></div>
div {
background-image: url("no-dimensions-1x1-ratio.svg");
background-size: contain;
}

MDN Playground에서 실행해보기 (Live Sample)
1:1 종횡비를 유지한 채, 넘치지 않도록 가장 작은 치수(여기선 높이 200px)에 맞춰 크기가 조절된 것을 알 수 있습니다.
<div></div>
div {
background-image: url("no-dimensions-1x1-ratio.svg");
background-size: cover;
}

MDN Playground에서 실행해보기 (Live Sample)
여기서는 가장 큰 치수(너비 300px)에 맞춰 꽉 차게 렌더링 됩니다. 1:1 비율이 유지되었지만, 이 원본 이미지(그라데이션)의 특성상 위아래가 잘려나간 걸 눈으로 완벽히 확인하기는 어려울 수 있습니다.
만약 background-size를 auto 혹은 auto auto로 설정하면, 알고리즘 2번 규칙에 의해 이미지에 포함된 고유 비율이 반드시 보존되어야 합니다.
고유 비율이나 치수가 하나도 명시되지 않은 배경 이미지를 자동 조절(auto)할 때는 4번 규칙이 작동합니다. 즉, 배경 영역 전체를 꽉 채우도록 이미지가 렌더링 됩니다.
<div></div>
div {
background-image: url("no-dimensions-or-ratio.svg");
background-size: auto auto;
}

MDN Playground에서 실행해보기 (Live Sample)
고유 비율은 없지만 최소한 하나의 치수가 SVG에 명시되어 있다면 3번 규칙이 발동합니다. 따라서 SVG에 적혀있는 그 치수를 따라 이미지가 렌더링 됩니다.
<div></div>
div {
background-image: url("100px-wide-no-height-or-ratio.svg");
background-size: auto auto;
}

MDN Playground에서 실행해보기 (Live Sample)
이 결과를 유심히 보세요. SVG 원본에 설정된 너비인 100px은 규칙대로 잘 적용되었지만, 높이는 아무것도 지정된 바가 없기 때문에 (비율조차도 없으므로) 결국 배경 영역의 높이(200px)를 꽉 채워버리게 됩니다.
고유 비율과 함께 고정 치수가 지정되어 있다면, 사실상 가로세로 치수가 모두 고정된 것과 다름없습니다. 앞서 언급했듯이 치수 하나와 비율을 알면 나머지도 자동으로 결정되니까요.
<div></div>
div {
background-image: url("100px-height-3x4-ratio.svg");
background-size: auto auto;
}

MDN Playground에서 실행해보기 (Live Sample)
이 이미지는 명시적인 높이가 100px입니다. auto 상황일 때 SVG 내부에 3:4 비율이 세팅되어 있으므로, 계산에 의해 너비는 75 픽셀이 됩니다.
SVG 쪽에 치수가 아예 없다면, 결국 CSS 쪽에 명시된 치수가 적용된 다음 2번 규칙에 따라 고유 비율을 이용해 나머지 치수를 선택하게 됩니다.
<div></div>
div {
background-image: url("no-dimensions-1x1-ratio.svg");
background-size: auto auto;
}

MDN Playground에서 실행해보기 (Live Sample)
알고리즘의 1번 규칙에 따라 CSS에서 명시된 치수는 무조건 최우선으로 사용됩니다. 따라서 우리는 나머지 auto로 남겨진 두 번째 치수가 어떻게 결정될지만 규칙을 통해 알아내면 됩니다.
이미지에 치수나 고유 비율이 아예 없다면 4번 규칙이 적용되어, 배경 박스 영역의 크기를 이용해 auto 치수의 값을 결정하게 됩니다.
<div></div>
div {
background-image: url("no-dimensions-or-ratio.svg");
background-size: auto 140px;
}

MDN Playground에서 실행해보기 (Live Sample)
여기서는 CSS에 의해 높이가 140px로 적용되었습니다(규칙 1). 그리고 4번 규칙에 따라 나머지 너비(auto 부분)는 배경 박스의 전체 너비인 300px로 결정됩니다.
만약 SVG 이미지에 지정된 치수가 1개 존재하고 고유 비율이 없다면, 그리고 하필 CSS 쪽에서는 그 치수를 auto로 설정했다면! 3번 규칙에 따라 SVG 내부에 적혀있던 그 치수가 존중되어 사용됩니다.
<div></div>
div {
background-image: url("100px-wide-no-height-or-ratio.svg");
background-size: auto 125px;
}
MDN Playground에서 실행해보기 (Live Sample)
여기서 너비(width)는 CSS에서 auto로 설정되었습니다. 따라서 3번 규칙에 의해 SVG 안에 명시되어 있던 너비 100px이 선택됩니다. 높이(height)는 CSS에 125px로 명시되어 있으므로 1번 규칙에 의해 이 값이 선택됩니다.
SVG에 치수 하나가 지정되어 있다면 1번 규칙에 따라 이 값이 일단 우선시되어 렌더링에 적용되지만, CSS에서 이를 명시적으로 덮어쓴다면 CSS 값이 최종 승리합니다. 여기에 고유 비율까지 있다면, 남은 한쪽의 auto 치수를 정하는 데 그 비율을 계산용으로 사용합니다.
<div></div>
div {
background-image: url("100px-height-3x4-ratio.svg");
background-size: 150px auto;
}

MDN Playground에서 실행해보기 (Live Sample)
이 경우, CSS에서 이미지의 너비를 150px로 고정해버렸습니다(규칙 1 적용). 그런 다음 auto로 설정된 높이 값을 구하기 위해 3:4라는 고유 종횡비를 활용하므로, 높이는 자동으로 200px이 됩니다.
SVG에 치수는 없고 고유 비율만 있는 상태에서 한쪽만 auto를 준다면, 먼저 CSS에 적힌 고정 치수가 적용되고, 이 값을 바탕으로 2번 규칙에 따라 고유 비율을 이용해 auto 치수를 알아냅니다.
<div></div>
div {
background-image: url("no-dimensions-1x1-ratio.svg");
background-size: 150px auto;
}

MDN Playground에서 실행해보기 (Live Sample)
CSS에 의해 너비는 150px로 설정됩니다. 높이는 auto로 지정되었으므로 1:1 종횡비를 활용해 너비와 똑같은 150px로 계산되어 렌더링 됩니다.
이 페이지가 도움이 되셨나요?
[Yes][No]
기여하는 방법 알아보기(Learn how to contribute)
이 페이지의 마지막 수정일은 2025년 11월 7일이며, MDN 기여자들에 의해 수정되었습니다.
👨🏫 마무리 강사 코멘트:
정말 복잡하죠? 외울 필요 전혀 없습니다. 핵심은 딱 이겁니다. "내 SVG 원본 코드가 어떻게 생겼는지 파악하고, CSS를 우선으로 먹일지 비율을 우선으로 먹일지만 고민하자!" 한번 MDN Playground에 들어가서 코드의 숫자를 이리저리 바꿔가며 실습해 보세요!