Границы SVG: измеряйте в правильных координатах
Сравните getBBox и getBoundingClientRect на преобразованной графике SVG. Правильно размещайте наложения, проверяйте границы обводки и подгоняйте viewBox с явным запасом.
На этой странице
- Выберите измерение под назначение
- Измерьте оригинальную преобразованную эмблему
- Рисуйте каждую рамку в ее системе координат
- Проверяйте параметры обводки вместо предположения о поддержке
- Преобразуйте локальную рамку перед подгонкой корневого viewBox
- Измеряйте геометрию, которую собираетесь редактировать
- FAQ
- Sources
Используйте getBBox(), когда нужны границы элемента SVG в его собственных пользовательских координатах. Используйте getBoundingClientRect(), когда нужен прямоугольник в CSS-пикселях относительно области просмотра браузера. Перед копированием любого результата в наложение или viewBox проверьте систему координат назначения.
У повернутой эмблемы может быть небольшая локальная рамка и гораздо большая рамка, выровненная по экрану. Оба измерения могут быть правильными. Ни одно не следует считать универсальным прямоугольником вокруг каждого закрашенного пикселя, особенно при наличии обводок, маркеров, обрезки или фильтров.
Выберите измерение под назначение
| Назначение | Начальное измерение | Что учитывать |
|---|---|---|
| Прямоугольник внутри той же системы координат SVG | getBBox() | Задайте прямоугольнику соответствующий контекст преобразования |
| Фиксированная HTML-рамка выделения | getBoundingClientRect() | Сохраняйте координаты области просмотра и обновляйте при изменении размещения |
| Корневой viewBox SVG вокруг преобразованной группы | Локальная рамка и преобразование координат | Переведите в пользовательские единицы корня перед подгонкой |
| Обрезка с учетом обводок и эффектов | Отдельно проверенный процесс определения границ | Не предполагайте, что базовая геометрическая рамка включает все оформление |
Документация 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>Локальные координаты идут от 0 до 140 горизонтально и от 0 до 60 вертикально. Отверстие влияет на внутреннюю часть фигуры, но не уменьшает внешние размеры.
Мы открыли геометрию в 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-рамки разместите div непосредственно под body с фиксированным позиционированием и без предка с преобразованием, задающего систему позиционирования:
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 }), но совместимость параметра options нужно рассматривать отдельно от давно существующего метода без аргументов.
В нашем тесте Chrome передача { stroke: true } вернула те же 140 × 60, что и вызов без аргументов. Удаление обводки 10 единиц также не изменило клиентский прямоугольник. Видимая темная граница явно изменилась, поэтому ни один результат в этом тесте не представлял полный закрашенный размер.
Принятие объекта options без ошибки недостаточно для доказательства выполнения параметра. Проверьте фигуру с известной обводкой и возвращенные размеры в целевом браузере. Используйте определения ограничивающих рамок SVG, чтобы различать границы объекта, обводки и оформленного объекта.
Не распространяйте правило отступа в половину обводки на все фигуры. Соединения miter, маркеры, немасштабируемые обводки, тени и фильтры могут расширяться иначе. Для простой контролируемой фигуры с круглыми соединениями может хватить явного запаса и визуальной проверки. Автоматическому инструменту обрезки экспорта эти случаи нужно обрабатывать осознанно.
Преобразуйте локальную рамку перед подгонкой корневого viewBox
Никогда не вставляйте x, y, width и height клиентского прямоугольника непосредственно в viewBox SVG. Эти значения включают положение на странице и используют другую систему единиц.
Для теста переведите четыре угла локальной рамки в пользовательские координаты корневого 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(" "));Это предполагает отрендеренный 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 bounding-box definitions — Различает геометрические границы объекта, обводки и оформленного объекта.
- MDN getScreenCTM — Описывает матрицу связи координат SVG и области просмотра.
Ещё из блога

Порядок transform в SVG: масштаб и положение графики
Сравните порядок translate и scale в SVG на измеренном примере логотипа. Используйте вложенные группы, проследите одну точку и разместите графику без изменения исходных контуров.

SVG-изображения Graphviz: переносимая графика узлов
Добавьте SVG-графику в узел Graphviz, проверьте ссылку на изображение и сравните полный комплект ресурсов, перенесенную диаграмму и автономную копию для передачи.