CSS и SVG маски
Разбираясь с возможностями оформления SVG, заинтересовалась темой масок.
Всё началось вот с этого эксперимента:
See the Pen SVG gradients for text by yoksel (@yoksel) on CodePen.
Для надписи подключен гуглошрифт, заливка сделана паттерном с градиентами, при этом надпись не перестала быть текстом — её можно выделить и скопировать!
Тут следует отметить, что гораздо проще было бы в качестве заливки использовать просто градиент, не заворачивая его в паттерн, но для этого нужно было задать градиенту свойство spreadMethod="repeat"
, чтобы он повторялся, а в Firefox в этом случае градиент почему-то ломался.
Я посмотрела на поддержку этого демо в разных браузерах, вспомнила про -webkit-background-clip: text
, который поддерживается только в вебкитах, и решила посмотреть что ещё есть интересного в этом направлении.
Есть несколько способов обрезать элемент по маске. Одни поддерживаются всеми современными браузерами, другие поддерживаются очень плохо, и пользоваться ими ещё нельзя. В некоторых способах маской может быть текст.
Используемые технологии:
- CSS — маска создается в CSS и применяется к HTML-элементам;
- SVG + CSS — SVG-маска применяется к HTML-элементам с помощью CSS;
- SVG — SVG-маска применяется к SVG-элементам. С помощью CSS, но главное здесь то, что и маска, и маскируемый элемент являются SVG.
Лучшая поддержка браузерами — у масок, сделанных полностью на SVG.
Не то, чтобы я глубоко изучала вопрос — мне хотелось увидеть все способы в одном месте и с информацией о браузерной поддержке, так что я сделала это демо — с примерами кода и ссылками на спецификации.
Все способы в нем представлены как есть — без фоллбеков, так что вы можете открыть страницу в интересующем браузере и посмотреть как в нем поддерживается нужный вам способ. Очень надеюсь, что однажды мы увидим все маски работающими во всех современных браузерах.
Маски бывают разных типов: одни позволяют обрезать элемент по векторной фигуре (пути) — clip
, clip-path
, другие ориентируются на яркость цветов или альфа-канал изображения — mask
и mask-image
— эти способы позволяют получить маску с размытыми краями.
Использовать текст в качестве маски можно в SVG clip-path
, SVG mask
, -webkit-background-clip
и SVG fill
. Последнее не является маской в прямом смысле слова, но результат выглядит как -webkit-background-clip
, и при этом поддерживается всеми современными браузерами.
Все маски вы можете найти на демо-странице, я же расскажу только про самые хорошо поддерживаемые — конечно же, все они на SVG. Все примеры в посте — живые демо, не скриншоты.
SVG clip-path для SVG элементов
clipPath
позволяет использовать векторную маску любой формы.
Применение SVG clipPath
для HTML-элементов поддерживается только в Firefox, но если перенести разметку в SVG — маска заработает во всех современных браузерах.
Фигуры внутри clipPath
можно комбинировать, чтобы получить более сложные, также в clipPath
может использоваться текст. Текст, использующийся в clipPath
, нельзя выделить и скопировать, при этом текст обрезаемого элемента — можно, правда, копируется он как-то странно.
SVG:
CSS:
SVG mask для SVG элементов
SVG mask
позволяет задать элемент или сочетание элементов, которые будут работать маской по альфа-каналу или по яркости. SVG mask
для HTML-элементов также поддерживается только в Firefox, но при переносе разметки в SVG работает везде.
Маской могут служить фигуры, при этом степень прозрачности зависит от яркости цвета заливки (светлые цвета — прозрачность, темные — непрозрачность). Фигуры, объявленные ниже в коде, обрезают слои, расположенные выше. Также в качестве маски можно использовать изображения.
SVG mask
(в отличие от clipPath
) позволяет сделать маску с размытыми краями.
SVG:
CSS:
SVG fill
fill
— заливка, а не маска, но позволяет довольно неплохо имитировать маски. Заливкой может цвет, градиент или паттерн.
Паттерн (pattern
) — это элемент SVG. В него можно положить всё что угодно, чтобы потом использовать содержимое контейнера как повторяющийся фон. В нем можно создать узор из других элементов SVG, а также завернуть в него картинку или текст.
Правда, с текстом есть некоторые трудности: в SVG текст не умеет переноситься сам по себе. Чтобы сделать текст с переносами, как в обычном HTML, его нужно завернуть в foreignObject
, но заливка с таким паттерном не работает, хотя в спеке для паттерна написано, что foreignObject
в паттерн вставлять можно.
Так что, чтобы сделать заливку текстом, надо вставить его через тег text
, а каждую строку завернуть в tspan
и задать ей нужное положение. Способ громоздкий, но работает.
Используя в качестве паттерна картинки, можно получить надписи с любой текстурой, которую подскажет ваша фантазия. При этом способ сработает во всех современных браузерах, в отличе от -webkit-background-clip: text
, так что фоллбеков потребуется сильно меньше.
Собственно, текст без заливки, но с текстурной обводкой тоже можно сделать: в этом случае паттерн следует задать свойству stroke
.
Примеры сделаны для текста, но fill
и stroke
точно также работают для фигур.
При использовании заливки для текста, текст всё ещё остается текстом: его можно выделить и скопировать (попробуйте на примерах ниже), ему можно задать размер и шрифт.
SVG:
CSS:
Важное уточнение: в Firefox и старой Опере ссылки вида mask: url(#masking);
не работают, если страница с SVG градиентами, паттернами и масками находится в одной директории, а CSS — в другой. Это лечится полным указанием пути от корня сайта, например mask: url(/page-url/#masking);
, чтобы браузеры знали где именно искать элемент с таким ID.
За указание на проблему спасибо legomushroom.
Возможности SVG позволяют делать самые разные маски и использовать их самыми разными способами, при этом они имеют очень неплохую поддержу браузерами. Если учесть, что многие свойства SVG можно анимировать с помощью JS, перспективы открываются очень интересные.