SVG 바운딩 박스: 올바른 좌표로 측정하기
변환된 SVG 그림에서 getBBox와 getBoundingClientRect를 비교하세요. 오버레이를 올바르게 배치하고 스트로크 경계를 테스트하며 명시적 여백으로 viewBox를 맞춥니다.
목차
SVG 요소 자체의 사용자 좌표 경계가 필요하면 getBBox()를 쓰세요. 브라우저 뷰포트 기준 CSS 픽셀 사각형이 필요하면 getBoundingClientRect()를 쓰세요. 결과를 오버레이나 viewBox에 복사하기 전에 대상 좌표계를 확인하세요.
회전 문양은 작은 로컬 상자와 훨씬 큰 화면 정렬 상자를 가질 수 있습니다. 둘 다 유효합니다. 특히 스트로크, 마커, 클리핑이나 필터가 있으면 어느 측정도 모든 칠해진 픽셀의 범용 사각형으로 취급하면 안 됩니다.
대상에 맞는 측정 선택하기
| 대상 | 시작 측정 | 필요한 주의 |
|---|---|---|
| 같은 SVG 좌표계 내부 사각형 | getBBox() | 사각형에 같은 변환 문맥 제공 |
| 고정 HTML 선택 외곽선 | getBoundingClientRect() | 뷰포트 좌표 유지, 레이아웃 변경 시 갱신 |
| 변환 그룹 주변 루트 SVG viewBox | 로컬 상자와 좌표 변환 | 맞춤 전에 루트 사용자 단위로 변환 |
| 스트로크·효과 포함 자르기 | 별도 검증한 경계 작업 흐름 | 기본 도형 상자가 모든 페인트를 포함한다고 가정하지 말 것 |
MDN getBBox() 문서는 로컬 도형 경계와 선택적 스트로크·마커·클리핑 제어를 설명합니다. 측정 요소 자체와 상위 요소 변환은 로컬 결과에 포함되지 않습니다. 그룹의 하위 요소는 그 안의 배치를 포함해 그룹 도형에 기여합니다.
MDN getBoundingClientRect() 참고 문서는 뷰포트 기준 좌표를 설명합니다. 스크롤이 그 관계를 바꿉니다. CSS 픽셀 값이 자동으로 SVG 사용자 단위나 물리 인쇄 치수가 되는 것은 아닙니다.

직접 만든 변환 문양 측정하기
예제는 직사각형 구멍의 청록색 고리와 별도 금색 삼각형입니다. 둘 다 두꺼운 둥근 연결 스트로크가 있습니다. 그룹에 이동, 회전과 크기 조절을 적용합니다.
<svg id="scene" width="600" height="300" viewBox="0 0 300 150"
xmlns="http://www.w3.org/2000/svg" style="overflow:visible">
<g id="art" transform="translate(100 35) rotate(25) scale(1.2)"
stroke="#17364c" stroke-width="10" stroke-linejoin="round">
<path fill="#147d78" fill-rule="evenodd"
d="M0 0H80V60H0Z M20 20H60V40H20Z" />
<path fill="#e5a340" d="M100 50L120 10L140 50Z" />
</g>
</svg>
<script>
const art = document.querySelector("#art");
const local = art.getBBox();
const screen = art.getBoundingClientRect();
</script>로컬 좌표는 가로 0140, 세로 060입니다. 구멍은 내부 모양을 바꾸지만 바깥 범위를 줄이지 않습니다.
Chrome에서 작은 테스트 도구로 도형을 측정했습니다. 600 × 300 CSS 픽셀 표시에서 getBBox()는 x=0, y=0, width=140, height=60을 반환했습니다. 클라이언트 사각형은 약 365.376 × 272.508 CSS 픽셀이었습니다. 화면 위치는 페이지의 SVG 위치에 달렸습니다.
표시 크기를 300 × 150으로 바꿔도 로컬 상자는 140 × 60이었습니다. 클라이언트 사각형은 약 182.688 × 136.254로 절반이 됐습니다. 원본 도형은 같고 페이지 매핑이 바뀌었습니다.
테스트 브라우저의 해당 예제 숫자입니다. 브라우저 엔진 비교나 모든 편집기 선택 상자의 명세는 아닙니다.
각 좌표계에 외곽선 그리기
로컬 외곽선은 반환 좌표와 측정 그룹의 같은 변환을 쓰세요. 다음 측정에 포함되지 않도록 형제로 배치하세요.
const scene = document.querySelector("#scene");
const box = art.getBBox();
const outline = document.createElementNS("http://www.w3.org/2000/svg", "rect");
for (const key of ["x", "y", "width", "height"]) {
outline.setAttribute(key, box[key]);
}
outline.setAttribute("transform", art.getAttribute("transform"));
outline.setAttribute("fill", "none");
outline.setAttribute("stroke", "olive");
scene.append(outline);그림·외곽선의 부모가 같아 이 예제에서는 직접 변환 복사가 적합합니다. 다른 위치에 삽입한 사각형은 두 좌표계 사이 행렬 매핑이 필요합니다.
HTML 외곽선은 변환된 상위 컨테이너 없이 body 바로 아래에 고정 위치 div를 두세요.
const box = art.getBoundingClientRect();
Object.assign(overlay.style, {
position: "fixed",
boxSizing: "border-box",
pointerEvents: "none",
border: "2px dashed coral",
left: `${box.x}px`,
top: `${box.y}px`,
width: `${box.width}px`,
height: `${box.height}px`,
});overlay는 기존 외곽선 요소입니다. 스크롤, 크기 변경이나 그림 레이아웃·변환 변경 시 다시 측정하세요. 문서 위치를 쓰면 스크롤 오프셋, 위치 지정 컨테이너를 쓰면 해당 좌표계를 반영하세요. 규칙 혼합은 올바른 사각형이 어긋나는 흔한 이유입니다.
테스트 도구는 두 외곽선을 표시했습니다. 로컬 사각형은 고리·삼각형과 기울고 점선 HTML 사각형은 수평·수직을 유지했습니다. 두꺼운 스트로크는 도형 외곽선 일부 밖으로 뻗었습니다.
지원을 가정하지 말고 스트로크 옵션 테스트하기
기본 로컬 상자는 스트로크 너비를 제외합니다. MDN은 getBBox({ stroke: true })를 설명하지만 옵션 매개변수는 오래된 인수 없는 메서드와 별도의 호환성 고려가 필요합니다.
Chrome 예제에서 { stroke: true }는 인수 없는 호출과 같은 140 × 60 상자를 반환했습니다. 10단위 스트로크 제거도 클라이언트 사각형을 바꾸지 않았습니다. 보이는 어두운 테두리는 분명히 바뀌었으므로 둘 다 전체 칠해진 범위를 나타내지 않았습니다.
오류 없이 옵션 객체를 받는다고 옵션 준수를 입증하지는 않습니다. 대상 브라우저에서 알려진 스트로크 도형과 반환 크기를 테스트하세요. SVG 바운딩 박스 정의로 객체, 스트로크와 장식 경계를 구분하세요.
모든 도형에 스트로크 절반 여백 규칙을 일반화하지 마세요. 마이터, 마커, 크기 고정 스트로크, 그림자와 필터는 다르게 뻗습니다. 제어하는 단순 둥근 연결 예제는 명시적 여백과 시각 검사로 충분할 수 있지만 자동 자르기 도구는 각 사례를 의도적으로 처리해야 합니다.
루트 viewBox 맞춤 전에 로컬 상자 변환하기
클라이언트 사각형의 x, y, width, height를 SVG viewBox에 직접 붙이지 마세요. 페이지 위치가 포함되고 단위계도 다릅니다.
예제의 로컬 상자 네 모서리를 루트 SVG 사용자 좌표로 매핑하세요. MDN getScreenCTM() 참고 문서는 SVG 좌표를 문서 뷰포트로 매핑하는 행렬을 설명합니다. 그림 행렬과 루트 역행렬을 결합하면 공통 화면 매핑을 제거합니다.
const box = art.getBBox();
const rootMatrix = scene.getScreenCTM();
const artMatrix = art.getScreenCTM();
if (!rootMatrix || !artMatrix) throw new Error("SVG is not measurable");
const toRoot = rootMatrix.inverse().multiply(artMatrix);
const corners = [
[box.x, box.y],
[box.x + box.width, box.y],
[box.x + box.width, box.y + box.height],
[box.x, box.y + box.height],
].map(([x, y]) => new DOMPoint(x, y).matrixTransform(toRoot));
const xs = corners.map(p => p.x);
const ys = corners.map(p => p.y);
const x = Math.min(...xs);
const y = Math.min(...ys);
const width = Math.max(...xs) - x;
const height = Math.max(...ys) - y;
const padding = 12; // Chosen for this simple fixture, in root user units.
scene.setAttribute("viewBox", [
x - padding, y - padding,
width + 2 * padding, height + 2 * padding,
].join(" "));역행렬이 있는 2차원 변환의 렌더링 SVG를 가정합니다. 로컬 사각형 모서리 매핑은 보수적인 축 정렬 외접 상자이며 모든 변환 곡선에 가장 꼭 맞는 상자는 아닐 수 있습니다.
해당 여백의 테스트 도구 viewBox는 약 57.571 23 206.688 160.254였습니다. 결과를 확인하니 둥근 스트로크가 표시 영역 안에 남았습니다. 맞춘 viewBox 비율이 달라 넓은 표시에는 옆 공간이 남았습니다. 맞춤은 늘어남을 뜻하지 않습니다.
자르기 대신 회전 중심이 필요하면 transform-origin 가이드가 참조 상자의 회전 영향을 설명합니다. 물리 가져오기 크기는 SVG 크기 문제 해결을 사용하세요.
편집할 도형 측정하기
소스가 PNG·JPG뿐이고 편집 도형이 필요하면 PerfectVector가 측정 전에 SVG를 복원할 수 있습니다. 경로, 구멍, 스트로크와 남은 래스터를 확인하세요. 바운딩 박스는 도형 범위를 알려 줄 뿐 추적 정확성이나 모든 세부의 편집 가능성을 입증하지는 않습니다.
기존 SVG는 직접 측정하세요. SVG 편집 가이드는 실제 내용 파악을 돕고 이미지 벡터화 개요는 앞 단계 변환을 설명합니다.
래스터 그림은 PerfectVector에서 원본을 시도하고 복원 윤곽선을 확인한 뒤 배치·내보낼 그룹을 측정하세요. 전달 자르기로 쓰기 전에 여백을 유지하고 최종 가장자리를 확인하세요.
FAQ
두 메서드의 너비가 다른 이유는 무엇인가요? 좌표계가 다릅니다. 로컬 SVG 상자는 사용자 단위 도형이고 클라이언트 사각형은 페이지 매핑 후 CSS 픽셀의 뷰포트 기준 경계입니다. 크기 조절·회전이 치수를 바꿀 수 있습니다.
바운딩 박스로 그림의 구멍을 알 수 있나요? 아닙니다. 사각형은 바깥 범위이며 내부 연결 구조가 아닙니다. 바깥 경계가 같은 채운 사각형과 고리는 같은 박스일 수 있습니다. 구멍은 경로·채우기 규칙을 검사하세요.
클라이언트 사각형을 viewBox로 써도 되나요? 직접은 안 됩니다. 관련 도형을 루트 SVG 사용자 좌표로 먼저 변환하세요. 화면 위치·CSS 픽셀 크기를 소스 좌표 사각형에 복사하면 안 됩니다.
Sources
- MDN getBBox — 로컬 SVG 경계와 선택적 측정 제어를 정의합니다.
- MDN getBoundingClientRect — 뷰포트 기준 사각형과 스크롤을 설명합니다.
- SVG 바운딩 박스 정의 — 객체, 스트로크와 장식 도형 경계를 구분합니다.
- MDN getScreenCTM — SVG·뷰포트 좌표 연결 행렬을 설명합니다.

