SVG-маски
SVG-маски — это очень богатая тема. В SVG есть два способа обрезать один элемент с помощью другого: это clip-path и mask. Clip-path для обрезки использует только контуры фигур, игнорируя заливки и обводки, с масками всё гораздо интереснее: в них учитываются и заливки, и обводки, и яркость содержимого. Более того, в маску можно вставить растровое изображение, и тогда для создания маски будут использоваться его темные и светлые участки.
Код самой простой маски выглядит вот так:
Добавим пару фигур для примера:
Картинка + маска = результат:
See the Pen JGyeZj by yoksel (@yoksel) on CodePen.
Код маски задаётся внутри SVG и может быть использован как внутри этого элемента, так и в других SVG-элементах на той же странице. Также есть возможность использовать SVG-маски в CSS (например, mask: url(#mymask)
), но на данный момент это работает только в Firefox.
Единственным обязательными атрибутом элемента mask
является id
— это идентификатор, который нужен для подключения маски к элементу, но есть и другие атрибуты:
maskUnits
Определяет, какая система координат будет использоваться для атрибутов x
, y
, width
и height
, то есть для внешних размеров и координат.
Возможные значения:
userSpaceOnUse
— используется текущая система координат элемента, к которому применяется маска. Если не применялись трансформации, соответствует системе координат всего документа (например, width: 100%
будет равно ширине всего SVG-элемента).
objectBoundingBox
— атрибуты x
, y
,
width
и height
задаются в частях или процентах от размеров элемента, к которому применяется маска (width: 100%
будет равно ширине элемента с маской).
Если maskUnits
не задано, используется значение objectBoundingBox
.
Попереключайте значения maskUnits
и посмотрите как меняется поведение маски:
See the Pen Coordinates in mask depends of maskUnits value by yoksel (@yoksel) on CodePen.
С objectBoundingBox
50% рассчитываются относительно элемента, с userSpaceOnUse
— относительно всего документа.
С objectBoundingBox
координаты и размеры можно задавать и в частях от целого, и в процентах, то есть .5
здесь то же самое, что и 50%
.
При userSpaceOnUse
будут работать только процентные значения либо значения в абсолютных единицах, например, в пикселях.
maskContentUnits
Определяет, какая система координат будет использоваться для содержимого маски, то есть для внутренних размеров и координат.
Возможные значения:
userSpaceOnUse
— для содержимого маски используется текущая система координат элемента, к которому применяется маска (без трансформаций соответствует системе координат всего SVG-элемента).
objectBoundingBox
— для содержимого маски используется система координат относительно элемента, все размеры и расстояния рассчитываются исходя из размеров элемента с маской.
Если атрибут maskContentUnits
не задан, используется значение userSpaceOnUse
.
See the Pen Coordinates in mask depends of maskContentUnits value by yoksel (@yoksel) on CodePen.
Обратите внимание, что при objectBoundingBox
фигуры могут искажаться (в данном случае круг превращается в эллипс).
В отличие от maskUnits
, при objectBoundingBox
координаты и размеры можно задавать только в частях от целого (возможные значения — от 0 до 1), значения в процентах работать не будут.
То есть не то чтобы совсем не будут — процентные значения будут рассчитываться относительно размеров всего SVG, и в этом случае .5
совсем не равно 50%
, потому что .5
— это половина элемента с маской, а 50%
— это уже половина всего SVG-изображения. И если вы будете менять значения maskContentUnits
, вам придётся каждый раз переписывать размеры и координаты содержимого маски.
Мне не сразу удалось понять как это работает, спасибо SelenIT2 и AmeliasBrain за то, что помогли разобраться в вопросе.
X и Y
Определяют, где будет находиться верхний левый угол отображаемой области маски. Содержимое маски при этом не сдвигается.
Для x
и y
значение по умолчанию 10%
.
See the Pen Mask x and y by yoksel (@yoksel) on CodePen.
Width и height
Определяют, где будет находиться нижний правый угол отображаемой области маски. Внешние размеры маски не влияют на размеры её содержимого.
Для width
и height
значение по умолчанию 120%
.
See the Pen Mask width and height by yoksel (@yoksel) on CodePen.
Вместе параметры x
,y
, width
и height
работают как viewBox
, то есть определяют размеры отображаемой области маски:
See the Pen X, Y, Width And Height by yoksel (@yoksel) on CodePen.
Знание всех этих технических подробностей позволит не сойти с ума при работе с масками и их своеобразными системами координат.
Примеры использования
Маски можно (и нужно) использовать для создания визуальных эффектов. Правда, мне пока не приходилось использовать маски в реальных проектах, но экспериментировать с ними очень увлекательно. Внимание: лучше всего демо отображаются в Opera и Chrome. В Firefox могут не работать некоторые анимации, в Safari воообще беда.
Например, с помощью маски можно вырезать фигуру нужной формы, анимировать её содержимое и собрать калейдоскоп.
Или привязать фигуру внутри маски к координатам курсора и получить фонарик (наведите курсор на демо):
See the Pen Flashlight by yoksel (@yoksel) on CodePen.
Ещё интереснее заворачивать в маску растровые изображения (в отличие от векторных, они могут быть любой сложности, с множеством деталей и мелких штрихов):
See the Pen Colorizing raster image with SVG Mask + SVG Filter by yoksel (@yoksel) on CodePen.
Автор совы: BioWorkZПодобное можно сделать с любой чёрно-белой картинкой, и для этого даже не придется открывать графический редактор.
See the Pen Leaf with pattern by yoksel (@yoksel) on CodePen.
Изображение в маске может быть анимированным (и заливка для него тоже!):
See the Pen Rainbow bird by yoksel (@yoksel) on CodePen.
(Если птица показалась вам знакомой, вам не показалось.)Также с помощью маски можно сделать анимированную заливку для текста:
See the Pen Dizzy dots by yoksel (@yoksel) on CodePen.
А ещё можно динамически менять векторное содержимое маски и сделать исчезающие надписи или, например, часы:
See the Pen Watches for summer (only seconds). SVG + JS by yoksel (@yoksel) on CodePen.
Или эффектную фотогалерею (туториал):
See the Pen Svg-masks by yoksel (@yoksel) on CodePen.
Маски удивительные, играться с ними можно до бесконечности. И, по-моему, они несут в себе огромный потенциал, который мы только-только начинаем открывать.