SVG-паттерны
- Содержание:
- patternUnits
- patternContentUnits
- patternTransform
- x, y
- width, height
- xlink:href
- Примеры кода
- Примеры паттернов
- Анимация
- Варианты использования
pattern
— это элемент, который можно использовать в качеcтве заливки или обводки. Содержимое паттерна может быть самым разным: фигуры, символы, текст или растровые изображения — в любых сочетаниях.
Самый простой пример кода выглядит вот так:
Помимо id
, без которого не получится применить паттерн к элементу, обязательно нужно указывать ширину и высоту паттерна, потому что по умолчанию их значения равны нулю (и паттерн не отобразится).
Добавим в паттерн какое-нибудь содержимое, например, вот такой кружок:
Сам по себе паттерн не отображается на странице. Чтобы увидеть паттерн в действии, его нужно применить к фигуре, это можно сделать, например, с помощью атрибута fill
:
Либо то же самое через CSS:
Результат:
See the Pen WoNQpZ by yoksel (@yoksel) on CodePen.
В основном примерах будут показываться паттерны в качестве заливки, но их так же можно использовать в обводках, тогда паттерн нужно задавать в свойстве stroke
.
Мы видим, что круг с координатами центра 50% 50%
находится посередине SVG-изображения, а не посередине фигуры с паттерном, также очевидно, что радиус 30%
рассчитывается относительно всего изображения, а не относительно фигуры, которой задана заливка. Такое поведение не всегда будет желаемым, и его можно менять с помощью атрибутов, которые будут описаны ниже.
Это самый простой вариант паттерна, он подойдёт если нужно, например, сделать просто заливку картинкой:
See the Pen ObJOLM by yoksel (@yoksel) on CodePen.
Для более сложных случаев нужно как следует разобраться с остальными свойствами паттерна.
patternUnits
Этот атрибут задаёт систему координат для внешних размеров паттерна, то есть влияет на атрибуты x
, y
, width
и height
.
Возможные значения:
userSpaceOnUse
— используется система координат родительского SVG-элемента. Если выбрано это значение, размеры и координаты можно задавать как в процентах, так и в единицах текущей системы координат;
objectBoundingBox
— используется система координат элемента, к которому применяется паттерн. Если выбрано это значение, размеры и координаты можно задавать в процентах или в значениях от 0.0 до 1.0.
По умолчанию patternUnits
использует значение objectBoundingBox
.
See the Pen patternUnits and pattern sizes by yoksel (@yoksel) on CodePen.
patternContentUnits
patternContentUnits
определяет систему координат для содержимого паттерна. Важно: если паттерну задан viewBox
, этот атрибут работать не будет.
Возможные значения:
userSpaceOnUse
— используется система координат родительского SVG-элемента. Если выбрано это значение, размеры и координаты можно задавать как в процентах, так и в единицах текущей системы координат;
objectBoundingBox
— используется система координат элемента, к которому применяется паттерн. Если выбрано это значение, размеры и координаты можно задавать только в числах от 0.0 до 1.0. Процентные значения здесь использовать не получится, потому что они очень странно себя ведут (подробнее можно почитать тут).
По умолчанию patternContentUnits
использует значение userSpaceOnUse
.
See the Pen patternContentUnits and pattern content by yoksel (@yoksel) on CodePen.
patternTransform
Атрибут позволяет добавить трансформацию паттерну.
По умолчанию в SVG центр трансформации (transform-origin
) находится в левом верхнем углу SVG-элемента. Для вращения (rotate
) можно вместе с углом поворота задать и центр трансформации, это выглядит примерно так:
Первое число — угол поворота, второе и третье — координаты центра вращения.
В этом коде координаты заданы в единицах текущей системы координат, это будет работать с patternUnits="userSpaceOnUse"
. При использовании patternUnits="objectBoundingBox"
координаты нужно задавать в относительных значениях в диапазоне от 0.0 до 1.0, код трансформации в этом случае должен быть таким:
Это должно работать, но не работает, как можно увидеть в демо ниже (потаскайте ползунок):
See the Pen patternTransform (and bug with transform-origin) by yoksel (@yoksel) on CodePen.
Эксперименты показали, что координаты центра трансформации в этом случае, как и при patternUnits="userSpaceOnUse"
, могут быть заданы в единицах текущей системы координат. Это будет работать, хотя и не должно.
Учитывая такое странное поведение, я бы рекомендовала не использовать patternTransform
вместе с patternUnits="objectBoundingBox"
.
x, y
Атрибуты позволяют задать положение плитки паттерна относительно верхнего левого угла:
See the Pen patternUnits and pattern coordinates (x & y) by yoksel (@yoksel) on CodePen.
width, height
Атрибуты определяют размер плитки паттерна, причём без viewBox
атрибуты не влияют на размеры содержимого, всё, что не поместилось, просто обрежется:
See the Pen patternUnits and pattern coordinates (width & height, no viewBox) by yoksel (@yoksel) on CodePen.
Если viewBox
задан, содержимое будет подгоняться под размер плитки паттерна, но с сохранением пропорций, заданных viewBox
. Если пропорции плитки и содержимого не совпадут, вокруг содержимого останется пустое пространство:
See the Pen patternUnits and pattern coordinates (width & height, has viewBox) by yoksel (@yoksel) on CodePen.
Если содержимое должно заполнять плитку целиком, пусть и с искажениями, нужно указать, что сохранять пропорции не требуется, для этого нужно добавить preserveAspectRatio="none"
:
See the Pen patternUnits and pattern coordinates (width & height, has viewBox + preserveAspectRatio="none") by yoksel (@yoksel) on CodePen.
Напомню, что по умолчанию ширина и высота паттерна равны нулю, поэтому размеры обязательно нужно указывать явным образом, иначе паттерн не отобразится.
viewBox, preserveAspectRatio
Если вы с ними не знакомы, в этом разделе будет немного вводной информации.
Эти атрибуты не являются специфичными для паттернов, они также могут использоваться как для некоторых других элементов внутри родительского SVG, так и для него самого.
Содержимое SVG-изображения отрисовывается на бесконечном холсте, и по умолчанию видимая область совпадает с размерами самого SVG-элемента. Если задан viewBox
, уже он будет задавать размеры и координаты прямоугольника, определяющего видимую область. Если размеры видимой области, заданные во viewBox
, не совпадают с размерами SVG-элемента, видимая область растянется или сожмётся, чтобы вместиться целиком. Также этот атрибут определяет соотношение сторон, которое должно сохраняться при изменении размеров элемента. Подробнее про viewBox
можно почитать в спецификации.
preserveAspectRatio
отвечает за поведение содержимого при изменении размеров родительского элемента, у него для этого есть большой набор разных значений. Значение по умолчанию — xMidYMid meet
, то есть содержимое должно помещаться целиком с сохранением пропорций (meet
) и выравниваться по центру (xMidYMid
). Схожим образом можно управлять поведением фоновых изображений с помощью background-size
или поведением одного элемента внутри в другого с помощью object-fit
.
Важно помнить, что preserveAspectRatio
не работает без viewBox
.
Узнать больше о значениях preserveAspectRatio
можно в спецификации.
При наличии viewBox
при ресайзе элемент стремится поместиться в заданную область целиком с сохранением пропорций. Если сохранять пропорции не нужно, задаётся атрибут preserveAspectRatio
со значением none
.
xlink:href
Как и некоторые другие SVG-элементы, паттерны могут наследовать свойства друг друга. Ссылка на паттерн, содержимое и свойства которого нужно унаследовать, задаётся в атрибуте xlink:href
.
Из паттерна по ссылке унаследуются все свойства и содержимое, которые не переопределены в текущем паттерне. В примере ниже правый паттерн наследует из левого содержимое и трансформацию:
See the Pen patternTransform and xlink:href by yoksel (@yoksel) on CodePen.
Примеры кода
Весь этот набор атрибутов не только позволяет гибко управлять паттерном, но и немного взрывает мозг при попытке их использовать.
По моему опыту, самый удобный код получается при одновременном использовании viewBox
, width
и height
. viewBox
определяет размер видимой области до применения какого-либо масштабирования, то есть какую часть содержимого паттерна нужно использовать как плитку — это немного похоже на применение инструмента «Crop» в фотошопе. Затем, указав ширину и высоту, можно управлять размером полученной плитки. То есть изначально плитка может быть любого размера, а нужный размер можно настроить потом.
Важный момент: чтобы между плитками не было пустых мест, нужно в width
и height
сохранять пропорции, указанные во viewBox
. Значения размеров при этом не должны зависеть от размеров фигуры или SVG-элемента, следовательно, нужно добавить ещё один необходимый атрибут — patternUnits
со значением userSpaceOnUse
(то есть нужно использовать систему координат всего SVG-элемента).
Пример кода:
Результат:
See the Pen patternUnits and pattern coordinates (width & height, has viewBox) by yoksel (@yoksel) on CodePen.
Изменяем размеры паттерна, он послушно масштабируется. При этом размеры фигуры на паттерн не влияют:
See the Pen width, height & viewBox + resize shape by yoksel (@yoksel) on CodePen.
Для своих экспериментов я обычно выбираю этот вариант, с ним удобнее работать.
А что если паттерн должен реагировать на изменение размеров элемента?
Вариант 1. Нужно задать атрибуту patternContentUnits
значение objectBoundingBox
. То есть внутри паттерна система координат должна строиться относительно элемента, к которому применён паттерн.
Пример кода:
Напомню, что при patternContentUnits="objectBoundingBox"
размеры и координаты внутри паттерна можно задавать только в числах от 0.0 до 1.0, проценты работать не будут. Так как все размеры содержимого задаются относительно размеров фигуры, тянуться они так же будут вместе с ней, без сохранения пропорций. Это видно на демо:
See the Pen width, height & viewBox + resize shape by yoksel (@yoksel) on CodePen.
Вариант 2. Он проще и удобнее, потому что содержимое паттерна сохраняет свою систему координат и единицы измерения. При этом способе patternUnits
не задаётся, потому что используется значение по умолчанию: objectBoundingBox
. Размеры плитки паттерна задаются в процентах или в значениях от 0.0 до 1.0, они будут зависеть от размеров фигуры. Чтобы содержимое паттерна ресайзилось вместе с ним, нужно добавить viewBox
, а чтобы оно при этом заполняло всю плитку, хоть и с искажениием пропорций, — preserveAspectRatio="none"
:
Результат:
See the Pen width, height & viewBox + preserveAspectRatio by yoksel (@yoksel) on CodePen.
Таким образом можно с минимальными усилиями сделать резиновый паттерн.
Примеры паттернов
Паттерн с растровой картинкой:
See the Pen eGAxK by yoksel (@yoksel) on CodePen.
Паттерн с векторным содержимым:
See the Pen SVG pattern by yoksel (@yoksel) on CodePen.
Паттерн с текстовым содержимым:
See the Pen WopeZb by yoksel (@yoksel) on CodePen.
Как видите, с помощью паттернов можно залить текст текстом : )
Все мои демо с паттернами собраны в этой коллекции.
Анимация
Содержимое паттернов можно анимировать с помощью CSS и Js. Анимации, сделанные с помощью Javascript, будут работать везде (демо), у CSS-анимаций могут быть проблемы с поддержкой браузерами.
В Firefox внутри паттерна не работают CSS-трансформации (вот демо, на котором можно потестить), — не работают и не анимируются, хотя они без проблем работают в Хроме. В некоторых случаях изменение размера фигуры можно имитировать управляя толщиной обводки. CSS-анимация заливки и обводки работает почти во всех браузерах, кроме IE (в IE11 не работает, в Edge не смотрела).
Примеры можно посмотреть в той же коллекции, многие демки содержат анимации.
Варианты использования
В паттерны можно завернуть практически всё что угодно. Их можно использовать не только для потворяющегося фона из обычных картинок, но и для более интересных и сложных штук. Внутри паттернов можно использовать конструкции из градиентов и символов, анимации могут находиться не только внутри паттерна, но и в используемых в нём компонентах, например, в градиентной заливке. Паттерны могут применяться к любым элементам внутри SVG, включая текст:
See the Pen Animated SVG pattern with GSAP by yoksel (@yoksel) on CodePen.
При этом сам паттерн, как мы видели в одном из предыдущих демо, тоже может содержать текст.
Элемент с паттерном может обрезаться маской, либо сам находиться внутри маски. Конструкции можно делать совершенно безумные.
С паттернами можно сделать много интересного, и, несмотря на некоторые сложности в использовании, они определённо стоят того, чтобы в них разобраться.
PS: Честно говоря, даже несмотря на относительно давнее знакомство с паттернами, они всё ещё вызывают у меня трудности. Тем не менее, если у вас возникнут вопросы, я постараюсь на них ответить.
- Ссылки по теме:
- Patterns
- Коллекция демо с SVG-паттернами