Маскирование в CSS
Оригинал: http://www.html5rocks.com/en/tutorials/masking/adobe/
Перевод: Влад Мержевич
В компьютерной графике отсечение и маскирование — это две наиболее используемые операции. Обе они визуально скрывают часть элемента. Если вы ранее работали с SVG или HTML Canvas, то эти операции для вас, скорее всего, уже не новы. Отсечение определяет область элемента которая будет видна, всё остальное за пределами этой области не отображается и получается «отрезанным». При маскировании изображение маски объединяется с элементом, влияя на его альфа-канал. Части маскированного элемента получаются полностью или частично прозрачными. Новая спецификация CSS Masking направлена на объединение этих двух операций в мире HTML.
Отсечение в CSS 2.1
В CSS 2.1 уже определено свойство clip, оно ограничено прямоугольной областью через функцию rect() которая принимает четыре аргумента расстояния для верхнего, правого, нижнего и левого краёв. Раздражающий момент: свойство clip применяется исключительно к абсолютно позиционированным элементам и просто игнорируется для других элементов.
CSS:
img {
position: absolute;
clip: rect(10px, 290px, 190px, 10px);
}
HTML:
<img src="image.jpg" width="568">
Свойство clip также ограничено отдельными элементами SVG. Это одна из причин, почему в спецификацию SVG добавлено свойство clip-path пригодное для маскирования в CSS.
Свойство clip-path
Свойство clip-path может применяться ко всем элементам HTML, графическим элементам и контейнерам SVG. Свойство либо ссылается на элемент <clipPath>, либо на одну из базовых фигур представленных в CSS Exclusions.
Элемент <clipPath> берёт любой графический элемент из SVG и использует его в качестве области отсечения. Графическими элементами в SVG являются <rect>, <circle>, <ellipse>, <path>, <polygon>, <image> и <text>. <clipPath> также позволяет комбинировать несколько графических элементов. Объединение всех фигур затем используется как область отсечения. Следующий пример демонстрирует использование <clipPath>:
CSS:
img {
clip-path: url(#clipping);
}
HTML:
<svg>
<defs>
<clipPath id="clipping">
<circle cx="284" cy="213" r="213" />
</clipPath>
</defs>
</svg>
<img src="image.jpg" width="568">
Базовые фигуры с другой стороны не требуют какой-либо разметки SVG. Они были добавлены к clip-path, чтобы предоставить удобные универсальные функции для простых операций отрезания.
- inset(<top> <right> <bottom> <left> [ round <border-radius> ]?) определяет прямоугольник похожий на фунцию rect() у свойства clip. В параметрах указывается смещение верхней, правой, нижней и левой сторон. Функция также имеет необязательный радиус скругления с синтаксисом как у свойства border-radius.
- circle(<r>? [ at <position> ]?) определяет простой круг с необязательным радиусом. Кроме того, необязательный параметр положения задаёт центральную точку окружности. <position> имеет тот же синтаксис, что и свойство background-position.
- ellipse(<rx> <ry>? [ at <position> ]?) определяет эллипс с горизонтальным и необязательным вертикальным радиусом, а также центральной точки на основе синтаксиса свойства background-position.
- polygon(<x1> <y1>, <x2> <y2>, ..., <xn> <yn>) определяет многоугольник основываясь на списке координат.
Ключевые слова вроде content-box, border-box, margin-box могут использоваться в сочетании с базовыми фигурами для изменения положения и размера указанного пути отсечения. Если ключевые слова применяются без базовых фигур, то они сами действуют как пути отсечения с учётом свойства border-radius. CSS разметка может выглядеть как в следующем примере:
img {
clip-path: polygon(0px 208px, 146.5px 207px, 147px 141.2px, ...);
}
Отсечение может быть весьма полезно для представления визуального контента. В следующих примерах к изображениям применяются различные операции отсечения.
Но отсечение может быть также полезным для разработки пользовательского интерфейса. В следующем примере зубчатый край указывает на продолжение списка.
- List Item 1
- List Item 2
- List Item 3
- List Item 4
- List Item 5
- List Item 6
- List Item 7
- List Item 8
- List Item 9
Прокрутите список для просмотра эффекта.
Обратите внимание, что clip-path (а также clip) действует на все характеристики элемента, включая фон, границы и механизм прокрутки.
Анимация clip-path
Базовые фигуры и содержимое элемента <mask> может быть анимировано. Следующий пример показывает анимацию фигуры в виде звезды.
Вот исходный код для анимации базовой фигуры:
img:hover {
clip-path: polygon(0px 208px, 146.5px 207px, 147px 141.2px, ...);
animate: star 3s;
}
@keyframes star {
0% {
clip-path: polygon(0px 208px, 146.5px 207px, 147px 141.2px, ...);
},
100% {
clip-path: polygon(0px 208px, 146.5px 207px, 147px 141.2px, ...);
}
}
Маскирование
Вторая операция после отсечения — это маскирование. Изображение маски используется в качестве своего рода «цветной сетки», которая фильтрует визуальные части элемента. В следующих абзацах я поясню разницу между двумя видами масок: маска по яркости и альфа-маска.
Маска по яркости
В маске по яркости вначале изображение маски преобразуется в чёрно-белое изображение (если оно ещё не такое). «Светлые» части маски сильнее маскируют элемент в том же месте. К примеру, чёрный цвет означает полную прозрачность, белый полную непрозрачность, а серые оттенки означают частичную прозрачность элемента.
Альфа-маска
Альфа-маска использует тот же принцип, что и маска по яркости. Разница между ними только в альфа-канале изображения. Чем меньше уровень прозрачности маски, тем больше виден элемент в той же точке.
Подведем итог: оба типа маскирования влияет на уровень прозрачности элемента. Изображение ниже является результатом обоих маскирующих операций показанных выше.
Спецификация CSS Masking описывает два универсальных свойства для маскирования: mask и mask-border.
Свойство mask
Свойство mask сочетает в себе изображение маски и ссылку на маску.
Первый способ заключается в использовании свойств mask-image, mask-repeat, mask-position, mask-clip, mask-origin и mask-size, которые определяются подобно частям background вроде background-image. Как и для background-image можно определить несколько исходников маски, каждый из них представляет собой изображение описанное в CSS3 Images. Все исходники маски будут объединены в единое изображение маски, далее оно используется чтобы замаскировать элемент и его содержимое, как описано выше. Изображение может быть в любом растровом формате вроде JPG или PNG, а также SVG или градиентом CSS. Приведённый выше пример с маской может быть просто реализован с помощью следующего кода:
img {
mask-image: url(mask.svg);
}
Если исходник маски должен быть растянут до размера содержимого, то просто используйте универсальное свойство mask как для фона, словно вы имеете дело со свойством background.
img {
mask: url(mask.svg) top left / cover;
}
Вторым способом является ссылка на элемент <mask>, который описан в SVG 1.1. Элемент <mask> берёт любой графический элемент, а также группу элементов из SVG и использует их для создания изображения маски.
CSS:
img {
mask: url(#masking);
}
HTML:
<svg>
<defs>
<linearGradient id="gradient" x1="0" y1="00%" x2 ="0" y2="100%">
<stop stop-color="black" offset="0"/>
<stop stop-color="white" offset="1"/>
</linearGradient>
<mask id="masking" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
<rect y="0.3" width="1" height=".7" fill="url(#gradient)" />
<circle cx=".5" cy=".5" r=".35" fill="white" />
</mask>
</defs>
</svg>
<img src="image.jpg" width="568">
В итоге это выглядит как такое изображение.
Свойство mask-border
Свойство mask-border позволяет разделить изображение маски на 9 фрагментов: четыре уголка, четыре края и средняя часть. Эти части могут разрезаться, масштабироваться и растягиваться разными способами в соответствии с размером маски. Свойство заимствует функциональность из border-image и обеспечивает эффективное маскирование краёв и углов содержимого. Следующий пример демонстрирует поведение свойства:
img {
-webkit-mask-box-image: url("stamp.svg") 35 repeat;
mask-border: url("stamp.svg") 35 repeat;
}
Следующее изображение применяется в качестве изображения маски и разделено на девять частей:
Эти части в данный момент используется для маскирования углов и краёв содержимого, в результате мы получим следующий вид:
Поддержка браузерами
Интересным моментом является поддержка в браузерах. Когда дело доходит до конкретной реализации всё становится довольно сложным.
Все браузеры поддерживают clip согласно спецификации. Все браузеры поддерживают свойства mask и clip-path для элементов SVG согласно спецификации SVG 1.1. Но только один браузер позволяет применять эти свойства для HTML-элементов: Firefox (вроде как). Рассмотрим подробнее.
Свойства clip-path и mask со ссылкой на <clipPath>, а также элемент <mask> работают в Firefox изначально без всяких префиксов. С другой стороны, mask-image, mask-border и связанные с ними свойства не поддерживаются вообще. Базовые фигуры для отсечения тоже не работают.
Blink и браузеры основанные на WebKit вроде Chrome и Safari поддерживают mask-image и mask-border (только они называются -webkit-mask-box-image в обоих случаях) и связанные с ними свойства. Все они пишутся с префиксами и могут применяться к элементам HTML. Ночные сборки обоих браузеров уже поддерживают свойство -webkit-clip-path для базовых фигур и ссылки на элемент <clipPath>. WebKit дополнительно поддерживает ключевое слово box-sizing.
Если вы хотите попробовать отсечение и маскирование, то используйте свойства как с префиксом, так и без него. Свойство без префикса должно ссылаться на <mask> или <clipPath> в настоящее время.
<style>
#image {
mask: url(#mask);
-webkit-mask: url(mask.svg) top left / cover;
}
</style>
<img id="image" src="coolImage.jpg" width="400">
<svg width="0" height="0">
<mask id="mask">
...
</mask>
</svg>
Будьте осторожны, другие браузеры ещё не понимают маскирование и отсечение для элементов HTML.