SVG-маски

Содержание:
maskUnits
maskContentUnits
x и y
width и height
Примеры использования

SVG-маски — это очень богатая тема. В SVG есть два способа обрезать один элемент с помощью другого: это clip-path и mask. Clip-path для обрезки использует только контуры фигур, игнорируя заливки и обводки, с масками всё гораздо интереснее: в них учитываются и заливки, и обводки, и яркость содержимого. Более того, в маску можно вставить растровое изображение, и тогда для создания маски будут использоваться его темные и светлые участки.

Код самой простой маски выглядит вот так:

<mask id="mask">
    <!-- содержимое маски -->
</mask>

Добавим пару фигур для примера:

<mask id="mask">
    <g stroke="gray" stroke-width="12" fill="white">
        <circle cx="33%" cy="30%" r="20%" />
        <circle cx="52%" cy="62%" r="32%" />
    </g>
</mask>

Картинка + маска = результат:

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 Kaleidoscope by yoksel (@yoksel) on CodePen.

Или привязать фигуру внутри маски к координатам курсора и получить фонарик (наведите курсор на демо):

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.

Маски удивительные, играться с ними можно до бесконечности. И, по-моему, они несут в себе огромный потенциал, который мы только-только начинаем открывать.

Ссылки по теме:
Clip path
Masking
CSS и SVG маски (статья)
Все виды масок в CSS и SVG (демо)
Анимированные SVG-маски
SVG: полезные ссылки
Множество демо с масками на Codepen
Если вы нашли ошибку или неточность, вы можете отредактировать статью с помощью prose.io, а также можно написать мне в комментариях или в Twitter.
Система комментирования от Disqus