Чтобы убрать неожиданное пространство вокруг экземпляра SVG use, определите, связано ли оно с исходным viewBox, подгонкой соотношения сторон или окружающей строкой CSS. В этом руководстве показано, как выявить и устранить каждую причину, сохранив предсказуемость координат размещения.
Задача заключается в небольшом изменении веб-страницы для настольного компьютера: точно разместить повторно используемую фигуру внутри SVG, а затем подогнать окружающую HTML-разметку. Примеры можно выполнить в обычном текстовом редакторе на Mac и открыть сохранённый HTML-файл в актуальном браузере для настольного компьютера.
Какая система координат определяет пространство?
Нужно проверить три границы: CSS-блок внешнего элемента SVG, область просмотра, используемую для ссылочного символа, и саму фигуру внутри этого символа. W3C чётко разграничивает область просмотра SVG и область просмотра CSS в браузере. viewBox преобразует пользовательские координаты SVG в область просмотра SVG; он не описывает окно браузера. Системы координат, преобразования и единицы измерения — SVG 2
Например, x="20" элемента use задаёт смещение в его системе координат SVG. Это не означает 20 пикселей CSS от левого края окна браузера. Масштабирование и преобразования предков могут изменить положение этого смещения на странице. Спецификация SVG описывает позиционирование use как дополнительный перенос, поведение которого отличается от компоновки CSS-блоков. Структура документа — SVG 2
Начните с этой таблицы решений. Это последовательность диагностики, основанная на описанных механизмах компоновки, а не перечень взаимозаменяемых исправлений.
| Что вы наблюдаете | Что проверить в первую очередь | Вероятное решение |
|---|---|---|
| Узкая полоса под всем SVG | Строчное форматирование и высоту строки родительского элемента | Сделайте отдельный SVG блочным или настройте его выравнивание в строке |
| Пустое пространство внутри каждой повторяющейся графики | Координаты фигуры и viewBox символа |
Уменьшите исходные границы, если отступ не нужен |
| Дополнительное пространство с двух сторон экземпляра символа | Размеры экземпляра и соотношение viewBox |
Согласуйте соотношения или выберите нужную политику подгонки |
| Правильное локальное положение, но неправильное положение на странице | Пользовательские единицы SVG и координаты области просмотра браузера | Преобразуйте координаты перед заданием x и y |
| Изменение размеров экземпляра ничего не меняет | Элемент, к которому применяется href |
Для подгонки используйте символ, задающий область просмотра, или преобразуйте геометрию |
Воспроизведите зазор на полном локальном примере
Сохраните этот полный документ как svg-spacing.html в обычном текстовом редакторе, затем откройте его в браузере. В нём используются только условные подписи и прямоугольники, без библиотек и внешних файлов. Светлые прямоугольники обозначают предполагаемые области просмотра экземпляров, а тёмные — повторно используемую графику.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SVG spacing example</title>
<style>
body {
margin: 24px;
font: 16px system-ui, sans-serif;
}
#canvas {
display: block;
width: 320px;
height: 200px;
outline: 1px solid #687580;
background: #fff;
}
.viewport-guide { fill: #e4edf2; }
.artwork { fill: #356b8c; }
text { fill: #253744; font-size: 14px; }
</style>
</head>
<body>
<p>Two instances with different source bounds and fitting dimensions.</p>
<svg id="canvas" xmlns="http://www.w3.org/2000/svg"
width="320" height="200" viewBox="0 0 320 200"
role="img" aria-labelledby="drawing-title">
<title id="drawing-title">Padded and tightly fitted rectangles</title>
<defs>
<symbol id="padded" viewBox="0 0 100 100">
<rect id="source-shape" class="artwork"
x="20" y="20" width="60" height="60" />
</symbol>
<symbol id="tight" viewBox="20 20 60 60">
<rect class="artwork"
x="20" y="20" width="60" height="60" />
</symbol>
</defs>
<rect class="viewport-guide"
x="20" y="20" width="120" height="60" />
<use href="#padded" x="20" y="20" width="120" height="60" />
<text x="160" y="55">Padded source</text>
<rect class="viewport-guide"
x="20" y="110" width="60" height="60" />
<use id="tight-instance" href="#tight"
x="20" y="110" width="60" height="60" />
<text x="110" y="145">Tight source</text>
</svg>
</body>
</html>
Для обоих экземпляров явно заданы размеры. Это позволяет при изучении зазора не полагаться на неявное определение размеров. В документации MDN сказано, что use повторно использует указанное содержимое SVG; также отмечено, что атрибуты width и height влияют на подгонку, если целевой элемент — SVG или символ с viewBox. В примере используется актуальный атрибут href. MDN: use
Рассчитайте, где на самом деле начинается первый прямоугольник
У первого источника viewBox размером 100 на 100, но его прямоугольник занимает только координаты от 20 до 80 по каждой оси. Запрошенная область просмотра экземпляра имеет размер 120 на 60. При подгонке по умолчанию xMidYMid meet масштаб равен меньшему из значений 120 / 100 и 60 / 100: 0.6. Подогнанный viewBox занимает 60 на 60 единиц, оставляя по 30 единиц с каждой стороны по горизонтали. Это следует из алгоритма преобразования области просмотра W3C. SVG 2: вычисление эквивалентного преобразования области просмотра SVG
Для этих наглядных исходных данных нарисованный прямоугольник начинается в точке 20 + 30 + 20 × 0.6 = 62 по горизонтали и 20 + 20 × 0.6 = 32 по вертикали. Его размер составляет 60 × 0.6 = 36 по каждой оси. Расчёт проверен небольшим детерминированным вычислением; это расчётные значения, а не результаты измерений в браузере.
Во втором экземпляре изменены два независимых параметра: исходные границы становятся 20 20 60 60, а область просмотра экземпляра — 60 на 60. Поэтому прямоугольник заполняет эту область просмотра и начинается в координате SVG (20, 110). Чтобы самостоятельно разделить причины, меняйте только один параметр за раз.
Как убрать пространство внутри экземпляра?
Исправьте нежелательные отступы в исходных границах
viewBox содержит четыре числа: минимальные x и y, ширину и высоту. Его начало координат не обязано совпадать с нулём. В примере viewBox="20 20 60 60" описывает существующие границы прямоугольника без изменения его геометрии. MDN: viewBox
Перед тем как уменьшать границы реальной графики, определите, намеренный ли в ней отступ. Набор повторно используемых фигур может иметь общую систему координат, чтобы их видимые размеры и положения оставались согласованными. Если уменьшить границы каждого символа отдельно, эти соотношения могут измениться. Сохраните общие границы, если такая согласованность предусмотрена дизайном.
Для проверки геометрии метод getBBox() возвращает границы в пользовательских координатах SVG. По умолчанию он не учитывает обводки и маркеры, а также преобразования, применённые к целевому элементу или его предкам. Поэтому ограничивающей рамки только по заливке недостаточно, чтобы судить об обрезке графики с обводками или преобразованиями. MDN: getBBox() для SVGGraphicsElement
Выберите способ подгонки при несовпадении соотношений сторон
Даже у графики с точно заданными границами может оставаться окружающее пространство, если квадратный исходник подгоняется под широкую область просмотра. Выберите политику в зависимости от нужного результата. Примените preserveAspectRatio к ссылочному символу, чтобы настроить внутреннюю подгонку, или к внешнему SVG при диагностике внешнего преобразования координат. MDN: preserveAspectRatio
| Вариант | Результат и условие |
|---|---|
| Совпадение соотношений исходника и области просмотра | Устраняет пространство, возникающее при подгонке соотношения сторон, и сохраняет пропорции |
xMidYMid meet |
Показывает весь viewBox по центру; при несовпадении соотношений остаётся пространство |
xMinYMin meet |
Сдвигает подогнанный viewBox к верхнему левому углу; оставшееся пространство сохраняется |
none |
Допускает неравномерное масштабирование; квадрат может превратиться в прямоугольник |
xMidYMid slice |
Заполняет область просмотра, но часть исходного содержимого выходит за её пределы; видимость зависит от обрезки |
Изменение выравнивания перемещает пространство, появившееся при подгонке; оно не убирает отступ, уже заложенный в исходную геометрию. Аналогично, slice не подходит, если всё исходное содержимое должно оставаться внутри области просмотра. Эти различия следуют из определений выравнивания, meet, slice и неравномерной подгонки в документации MDN. MDN: preserveAspectRatio
Проверьте целевой элемент, если размеры не дают эффекта
Обычная группа или контур не получают область просмотра для подгонки только потому, что на них ссылается элемент use. Согласно W3C, экземплярные width и height не действуют, если указанный элемент не создаёт новую область просмотра. Для предсказуемой подгонки каждого экземпляра поместите повторно используемую геометрию в символ с явными границами, как в примере выше. Для непосредственного геометрического масштабирования используйте преобразование и учитывайте его влияние на положение. SVG 2: компоновка повторно используемой графики
Как убрать полосу под внешним SVG?
Зазор за пределами SVG может возникать из-за строчного форматирования HTML. WHATWG допускает SVG в строчном содержимом, поэтому окружающая страница может размещать его рядом с текстом. Строки CSS учитывают метрики шрифта выше и ниже базовой линии, из-за чего под строчной графикой может оставаться видимое пространство. Стандарт HTML: SVG, CSS 2: расчёт высоты строки
В полном примере для #canvas уже задано display: block, что исключает SVG из участия в строчной строке. Для отдельного рисунка оставьте это правило. Чтобы изучить механизм, временно измените его на display: inline и проверьте окружающую строку.
Если SVG должен оставаться рядом с текстом, попробуйте задать внешнему SVG vertical-align: bottom и проверьте выравнивание текста. Это свойство выравнивает строчный блок внутри строки; оно не меняет границы символа или внутреннюю подгонку. На общую высоту строки по-прежнему могут влиять другое содержимое и высота строки родительского элемента. MDN: vertical-align
Рассматривайте эти объявления CSS как альтернативы для внешнего SVG, а не как набор исправлений, которые нужно добавлять к каждому экземпляру:
/* Standalone drawing */
#canvas {
display: block;
}
/* Alternative when the drawing must stay inline */
/*
#canvas {
display: inline;
vertical-align: bottom;
}
*/
Что делать, если координаты получены из области просмотра браузера?
getBoundingClientRect() возвращает положение элемента относительно области просмотра браузера в пикселях CSS. При прокрутке страницы это положение меняется. Эти значения относятся к другой системе координат, чем пользовательские координаты SVG, поэтому напрямую копировать left и top в x и y экземпляра, как правило, неправильно. MDN: getBoundingClientRect() элемента
Если исходными данными служит точка из области просмотра браузера, используйте преобразование координат. getScreenCTM() предоставляет матрицу преобразования SVG, а её обратная матрица преобразует точку обратно в локальные координаты выбранного элемента. Метод matrixTransform() точки выполняет это преобразование. MDN: getScreenCTM(), MDN: matrixTransform()
Следующий фрагмент для консоли — необязательное дополнение к полному документу выше. Он преобразует точку области просмотра браузера (100, 150) в пользовательские координаты внешнего SVG и перемещает туда экземпляр с точно заданными границами. Предполагается, что экземпляр из примера без преобразований остаётся непосредственным дочерним элементом этого SVG.
(() => {
const canvas = document.getElementById("canvas");
const instance = document.getElementById("tight-instance");
if (!canvas || !instance) {
throw new Error("Open the complete SVG spacing example first.");
}
const matrix = canvas.getScreenCTM();
if (!matrix) {
throw new Error("The SVG coordinate matrix is unavailable.");
}
const viewportPoint = new DOMPoint(100, 150);
const localPoint = viewportPoint.matrixTransform(matrix.inverse());
if (!Number.isFinite(localPoint.x) || !Number.isFinite(localPoint.y)) {
throw new Error("The SVG coordinate matrix cannot be inverted.");
}
instance.setAttribute("x", String(localPoint.x));
instance.setAttribute("y", String(localPoint.y));
})();
Проверка конечных чисел важна, поскольку необратимая матрица даёт компоненты NaN. При преобразовании новой точки пересчитывайте матрицу после изменения компоновки или прокрутки. Если экземпляр находится внутри преобразованной группы, преобразуйте координаты в систему этой родительской группы. Этот фрагмент был сверён с документацией API, но во время исследования не запускался в браузере. MDN: inverse() интерфейса DOMMatrixReadOnly
В конце отдельно проверьте три границы: внешний блок SVG, подогнанную область просмотра символа и собственные границы графики. Исправьте ту границу, которая создаёт нежелательное пространство, а затем проверьте результат при нужном размере страницы. Так можно точно размещать элементы, не компенсируя необъяснимый зазор произвольными смещениями.
Источники
- Системы координат, преобразования и единицы измерения — SVG 2 — W3C.
- Структура документа — SVG 2 — W3C.
use— MDN Web Docs.- viewBox — MDN Web Docs.
- preserveAspectRatio — MDN Web Docs.
- SVGGraphicsElement: метод getBBox() — MDN Web Docs.
- Стандарт HTML — SVG — WHATWG.
- Подробности модели визуального форматирования — W3C.
- Свойство CSS vertical-align — MDN Web Docs.
- Element: метод getBoundingClientRect() — MDN Web Docs.
- SVGGraphicsElement: метод getScreenCTM() — MDN Web Docs.
- DOMPointReadOnly: метод matrixTransform() — MDN Web Docs.
- DOMMatrixReadOnly: метод inverse() — MDN Web Docs.