Размеры в SVG
Управление размерами — тема важная, и чтобы максимально использовать возможности SVG, нужно хорошо понимать как всё работает.
Вьюпорт
Содержимое SVG-элемента отрисовывается на бесконечном холсте и может быть сколь угодно большого размера, но видимая часть холста соответствует размерам SVG-элемента. Эта область отрисовки называется viewport
(вьюпорт).
SVG позволяет управлять как размерами вьюпорта, так и поведением содержимого относительно него: оно может обрезаться или показываться полностью, может растягиваться с потерей пропорций или стараться уместиться целиком, даже если при этом появляются пустые поля. Этим поведением можно управлять с помощью атрибутов.
Если просто вставить SVG на страницу и не задавать ему никакие размеры, он отобразится размером 300px на 150px, что не поместилось — обрежется:
See the Pen SVG without any attributes by yoksel (@yoksel) on CodePen.
Ширина и высота
Шириной и высотой элемента можно управлять стандартными свойствами width
и height
:
Их можно задавать как атрибутами, так и в CSS:
Для размеров в пикселях, задаваемых в атрибутах, единицы измерения можно не указывать.
See the Pen SVG with width & height by yoksel (@yoksel) on CodePen.
Потаскайте ползунки, и вы увидите, что изменение ширины и высоты влияет только на вьюпорт и не влияет на содержимое, потому что оно отрисовывается на бесконечном холсте, и неизвестно область какого размера нужно ресайзить.
viewBox
Похожим образом не изменяя размеры содержимого ресайзится iframe
, но в случае с SVG это поведение можно изменить, если определить размеры области с помощью свойства viewBox
:
Первые два значения — координаты X и Y верхнего левого угла отображаемой области, последние два — ширина и высота. viewBox
задаётся только атрибутом.
Попробуйте теперь изменить размеры, и вы увидите, что содержимое отресайзится, чтобы поместиться целиком.
See the Pen SVG with width, height & viewBox by yoksel (@yoksel) on CodePen.
viewBox
можно использовать, например, для кадрирования изображения, чтобы показывать не всю картинку, а только какую-то её часть:
See the Pen SVG with width, height & viewBox (change viewBox) by yoksel (@yoksel) on CodePen.
Это очень простое демо, вот пример посложнее от Sarah Drasner.
Интересно, что если у SVG нет размеров, но задан viewBox
, изображение займёт собой всё доступное пространство:
See the Pen SVG with viewBox by yoksel (@yoksel) on CodePen.
Это поведение может стать проблемой: если размеры у иконок задаются в стилях, а они не загрузились — страница может превратиться в парад гигантских SVG-иконок. Чтобы этого не произошло, всегда явно задавайте в атрибутах SVG ширину и высоту, их потом легко переопределить в CSS.
preserveAspectRatio
Как мы видели в примере выше, если у SVG заданы размеры и viewBox
, содержимое будет сжиматься и растягиваться с сохранением пропорций, чтобы поместиться целиком, но этим поведением тоже можно управлять — с помощью свойства preserveAspectRatio
(оно задаётся только атрибутом).
Например, с помощью значения none
можно указать, что сохранять пропорции не нужно:
See the Pen SVG preserveAspectRatio='none' by yoksel (@yoksel) on CodePen.
SVG с viewBox
и preserveAspectRatio='none'
ведёт себя очень похоже на img
: при изменении размеров содержимое масштабируется под размеры вьюпорта не сохраняя пропорции.
none
будет полезно для резиновых фонов:
See the Pen SVG background with & without preserveAspectRatio by yoksel (@yoksel) on CodePen.
Остальные значения preserveAspectRatio
состоят из двух частей: первая задаёт выравнивание, вторая — поведение элемента относительно вьюпорта.
Выравнивание задаётся одним значением, определяющим положение по вертикали и по горизонтали, например: xMaxYMin
. Для обеих осей можно задать положение в начале, в середине и в конце:
xMin
, YMin
— в начале оси
xMid
, YMid
— в середине
xMax
, YMax
— в конце
Эти значения можно комбинировать в любых сочетаниях, но порядок должен сохраняться: первым всегда идет значение для X, вторым для Y. Значение для Y всегда пишется с большой буквы.
Поведение элемента определяется второй частью preserveAspectRatio
. Возможные значения:
meet
— содержимое стремится уместиться целиком (как фон с background-size: contain
)
slice
— содержимое заполняет собой всю область видимости (как background-size: cover
: что не поместилось, обрежется)
See the Pen SVG preserveAspectRatio values by yoksel (@yoksel) on CodePen.
Важно помнить, что preserveAspectRatio
не работает без viewBox
. viewBox
задает область, которая должна масштабироваться, preserveAspectRatio
определяет как именно она должна это делать.
Также нужно понимать, что preserveAspectRatio
срабатывает, если вьюпорт и вьюбокс имеют разные соотношения сторон. Если соотношения сторон совпадают, и содержимое умещается без полей, preserveAspectRatio
работать не будет (в этом случае в нём просто нет необходимости).
Для использования SVG в качестве иконок достаточно viewBox
и размеров, но если предполагается делать что-то более сложное, имеет смысл разобраться с единицами измерения и системой координат.
Единицы измерения
Внутри SVG можно использовать em
, ex
, px
, pt
, pc
, cm
, mm
, in
, проценты, а также единицы системы координат (user space units). Единицы системы координат соответствуют пикселям, поэтому для значений в пикселях единицы измерения указывать не нужно.
Системы координат
В SVG-документе есть две системы координат:
- Система координат области отрисовки — viewport space.
- Система координат содержимого — user space.
Отсчет системы координат вьюпорта начинается от левого верхнего угла вьюпорта, системы координат содержимого — от левого верхнего края вьюбокса.
По умолчанию система координат содержимого соответствует системе координат вьюпорта, а единицы измерения содержимого — единицам измерения вьюпорта, но при использовании трансформаций или viewBox
масштабируется вся система координат с единицами измерения, то есть пиксели из user space больше не равны пикселям из viewport space.
Поизменяйте размеры элемента и посмотрите что происходит с системой координат содержимого (она показана бирюзовым):
See the Pen SVG with & coordinates by yoksel (@yoksel) on CodePen.
Система координат содержимого начинается из точки 0,0, и если вьюпорт и вьюбокс не совпадают, точка отсчета, как и вся система координат содержимого, будет ездить и масштабироватся вместе с вьюбоксом.
Масштабирование единиц измерения хорошо видно на примере обводки: изначально её толщина равна единице, но при изменении размеров видимая толщина обводки будет изменяться вместе с фигурой:
See the Pen SVG with width, height & viewBox + stroke by yoksel (@yoksel) on CodePen.
Если такое поведение нежелательно, это можно исправить с помощью свойства vector-effect
со значением non-scaling-stroke
, оно добавляется к содержимому SVG:
See the Pen SVG with width, height & viewBox + stroke by yoksel (@yoksel) on CodePen.
vector-effect
можно задавать как атрибутом, так и в CSS.
Также новая система координат создается при добавлении трансформаций:
See the Pen SVG with transform & coordinats by yoksel (@yoksel) on CodePen.
Внутри трансформируемого элемента будет своя своя система координат, отличная от систем координат вьюпорта и вьюбокса.
Тема может выглядеть сложной, но на самом деле, достаточно немного поиграться с кодом, и всё станет понятно. Для лучшего понимания систем координат, размеров и трансформаций в SVG рекомендую демо Сары Суайдан, а также её статьи:
- Understanding SVG Coordinate Systems and Transformations (Part 1) — The viewport, viewBox, and preserveAspectRatio
- Understanding SVG Coordinate Systems and Transformations (Part 2) — The transform Attribute
- Understanding SVG Coordinate Systems and Transformations (Part 3) — Establishing New Viewports
- Ссылки по теме:
- Coordinate Systems, Transformations and Units
- Метки:
- SVG