![](https://habrastorage.org/webt/nn/tp/af/nntpafof0gvulj0y3k55_cdlrw0.png)
В мире дизайна маскирование является популярной техникой реализации уникальных эффектов. Будучи дизайнером, я сам использовал эту технику много раз, но не очень часто в веб-среде. Думаю, что от её применения на сайтах меня удерживала недостаточная поддержка браузерами. Полноценно этот функционал поддерживается в Safari и Firefox, а вот в браузерах на движке Blink (Chrome и Edge) — лишь частично.
Радует то, что тема CSS маскирования будет частью Interop 2023, а значит, вскоре можно ожидать кросс-браузерную поддержку этой возможности (Вау!).
В текущей статье я проговорю, что вообще такое CSS маскирование, объясню, как оно работает, а также приведу некоторые примеры использования.
Поехали!
Содержание
- Что такое маскирование?
- Как применять маски в CSS?
- Маскирование с использованием градиентов
-
Практические примеры
- Заключение
- Дополнительные ресурсы
Что такое маскирование?
В своей сути маскирование подразумевает скрытие части элемента без его стирания.
Взгляните на этот рисунок:
![](https://habrastorage.org/webt/ac/y1/qq/acy1qqymhmtrd7umk6n2ppn6elw.png)
Здесь у нас изображение и маска. В приложениях для дизайна вроде Photoshop можно вставлять изображение в серую фигуру, получая его маскированную форму.
Принцип заключается в скрытии некоторых частей изображения без их стирания.
![](https://habrastorage.org/webt/mz/p6/tc/mzp6tczj9hohqnyyxzxv9d9izqa.png)
Это основной принцип маскирования, подразумевающий использование некой фигуры (маски) для показа/скрытия частей элемента. При этом также существуют более глубокие и более уникальные способы маскирования контента.
Например, можно создать градиентную маску:
![](https://habrastorage.org/webt/u1/jp/ec/u1jpecbzw2_zu3vupjqz4wdrako.png)
В градиенте присутствуют закрашенные и прозрачные пиксели. Закрашенные соотносятся с видимыми частями элемента, а прозрачные — со скрытыми.
![](https://habrastorage.org/webt/sp/ct/ht/spcthtmu7pgtgs5jc7gnkpv5jjo.png)
В Photoshop можно добавлять слой маски к целой группе слоёв, таким образом применяя его к содержимому этой группы. При этом для маскирования части группы используется инструмент «кисть».
![](https://habrastorage.org/webt/qb/sw/gj/qbswgjo2-oe_apbvzzrhss884e4.png)
Маскированное содержимое не стирается, а лишь скрывается (обратите внимание на элементы группы).
Хорошо, теории хватит. Далее мы разберём способы маскирования в CSS.
Как применять маски в CSS
В CSS есть несколько способов для маскирования элементов:
- свойство
mask
; - свойство
clip-path
; - SVG <mask>.
Основное отличие между свойствами
mask
и clip-path
в том, что первое используется для изображений и градиентов, а второе для путей. В этой статье акцент будет сделан на свойстве mask
.Его можно назвать сокращённым вариантом свойства
background
, но со своими особенностями.Вместо перечисления всех свойств маскирования в CSS, я покажу пример с поэтапным добавлением маски, чтобы вы могли визуально увидеть разницу.
Применение
background
выглядит так:.card__thumb {
background-image: url('hero-cool.png');
}
А применение маски так:
.card__thumb {
mask-image: url('hero-cool.png');
}
![](https://habrastorage.org/webt/kg/ie/sd/kgiesdogmkq2yovfj4t4xwrnr0y.png)
Круто, правда? Такой подход существенно упростит понимание и запоминание масок.
Теперь повторим в CSS наш первый пример.
Для начала нужно экспортировать фигуру в виде изображения png.
![](https://habrastorage.org/webt/ui/jk/-1/uijk-1g0fbtisv7_y4qbyuqnlnu.png)
Предположим, я хочу применить к этому изображению маску.
<img src="ahmad-shadeed-web-directions.jpg" alt="" />
img {
mask-image: url("shape.png");
}
Можете предположить, какой получится результат? По умолчанию маска будет повторяться, и её размер будет соответствовать размеру её изображения. Сейчас результат получится такой:
![](https://habrastorage.org/webt/ct/ed/uj/ctedujl6wh5kgsvbst1dlg_la28.png)
Чтобы это исправить,
mask-repeat
, как и в случае с фоновыми изображениями, нужно установить на no-repeat
.img {
mask-image: url("shape.png");
mask-repeat: no-repeat;
}
![](https://habrastorage.org/webt/0p/_-/vr/0p_-vrh8gqsgqehmgkrjj60cs0g.png)
Прекрасно! Заметьте, что маска оказалась в верхнем левом углу. Её положение можно изменить с помощью
mask-position
. Опять же, обратите внимание, что синтаксис идентичен синтаксису для фоновых изображений.img {
mask-image: url("shape.png");
mask-repeat: no-repeat;
mask-position: center;
}
![](https://habrastorage.org/webt/nv/2a/vo/nv2avomfstrh0ctfvzy1ubgk_-a.png)
Помимо расположения маски, также можно изменять её размер. Это позволяет делать изображение маски отзывчивым к размеру элемента.
img {
mask-image: url("shape.png");
mask-repeat: no-repeat;
mask-position: center;
mask-size: 60%;
}
![](https://habrastorage.org/webt/r6/r2/cr/r6r2cr8aobeuxgh4p7zg0y0kcrm.png)
У масок есть и некоторые другие свойства, но пока я не хочу вас ими перегружать, поэтому лучше покажу их позднее уже на реальных примерах.
Маскирование с использованием градиентов
В CSS маскирование – это не просто использование изображения. Здесь мы также можем задействовать градиенты для создания мощных и полезных эффектов.
Чуть позже я покажу некоторые интересные примеры, а пока хочу сосредоточиться на основных принципах работы градиентов при маскировании.
В следующем примере
mask-image
состоит из линейного градиента, переходящего от чёрного к прозрачному.img {
mask-image: linear-gradient(#000, transparent);
}
![](https://habrastorage.org/webt/tx/ly/-1/txly-1ylx_h-9pfcg93x9mqvqia.png)
Из MDN:
По умолчанию это означает, что альфа-канал изображения маски, будет умножен на альфа-канал элемента. Управлять этим можно с помощью свойстваmask-mode
.
То есть вы можете использовать для маски любой цвет, поскольку предустановленный режим маскирования установлен на
alpha
(позднее я поясню это более подробно).img {
mask-image: linear-gradient(red, transparent);
}
![](https://habrastorage.org/webt/dl/by/ot/dlbyotyu9-qdwu7uvtzwntbbvvm.png)
Опять же, принцип маскирования заключается в скрытии содержимого прозрачными пикселями. Вот упрощённый пример градиента с жёстким переходом цвета:
img {
mask-image: linear-gradient(#000 50%, transparent 0);
}
![](https://habrastorage.org/webt/ls/1h/lj/ls1hljs0zdc0aed3le8sskn00mi.png)
Отлично! Теперь, когда мы разобрались с основными принципами маскирования, предлагаю рассмотреть несколько практических случаев применения масок в CSS.
Практические примеры
▍ Затухание изображения
В качестве интересного варианта применения маскирования можно привести затухание изображения при его смешивании с фоновой картинкой.
Взгляните на эту картинку:
![](https://habrastorage.org/webt/de/8h/pe/de8hpedau0vppc7mhhar_bmic2u.png)
На первый взгляд тут можно добавить градиент с тем же цветом, что и фон. Например, так:
.hero__thumb:after {
position: absolute;
inset: 0;
background: linear-gradient(to top, #f1f1f1, transparent)
}
И хотя такой вариант может сработать, при изменении фонового цвета всё нарушится. Обратите внимание, что hero-изображение теперь имеет жёсткий переход:
![](https://habrastorage.org/webt/g4/bp/t0/g4bpt0jzy8swcz3wyr_z6cz9lvm.png)
В качестве альтернативы можно маскировать hero-изображение так, чтобы оно работало с любым цветом фона.
.hero__thumb {
mask-image: linear-gradient(#000, transparent);
}
Вот и всё! Теперь эффект затухания реален и при изменении фона основной страницы не нарушится.
![](https://habrastorage.org/webt/nn/tp/af/nntpafof0gvulj0y3k55_cdlrw0.png)
▍ Маскирование текста: пример 1
Когда нам нужно изобразить длинный текст, но пространства под него не хватает, в качестве решения можно сделать его затухание в начале и конце. В итоге невидимую часть текста можно будет просматривать посредством анимирования в обоих направлениях.
Возьмём следующий рисунок:
![](https://habrastorage.org/webt/1_/dn/ea/1_dneaa3xhsic9dy179hcil20_w.png)
Опять же, простое использование градиента здесь не сработает, потому что фоновое изображение будет меняться. Это может быть сплошной цвет или картинка.
![](https://habrastorage.org/webt/lu/_t/ep/lu_tepqofd89wasijvgkifvut5g.png)
Чтобы реализовать такой макет в CSS, нужно добавить градиентную маску, которая приведёт к затуханию содержимого в начале и конце.
Мне нравится сначала реализовывать сам градиент для предварительной визуальной оценки и уже потом применять его в качестве маски.
.c-card__footer {
background-image: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent 100%);
}
![](https://habrastorage.org/webt/bg/yc/il/bgycilqjt1fztcnzgybxo_jzpho.png)
Градиент готов. Теперь можно задействовать его в качестве маски:
.c-card__footer {
mask-image: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent 100%);
}
Получилось не идеально? Можно поэкспериментировать со значениями градиента, пока не будет достигнут желаемый результат.
▍ Маскирование текста: пример 2
Это тот же пример, но теперь градиент будет вертикальным. Я видел такое в роликах на Instagram.
Взгляните на следующее изображение:
![](https://habrastorage.org/webt/7b/1q/3h/7b1q3hneird1t0pe4npeqan_h54.png)
Обратите внимание, что верхняя часть текста размывается. В этой небольшой области могут находиться комментарии к ленте, действия и прочее. Маскирование идеально для этого подойдёт.
Для начала посмотрим на сам градиент.
![](https://habrastorage.org/webt/ek/zx/sc/ekzxscc52fi8abi4tywv60mdvqk.png)
В CSS это может выглядеть так:
.whatever-the-class-name {
mask-image: linear-gradient(to bottom, transparent, #000);
}
▍ Маскирование списков
Изучая тему масок в CSS, я наткнулся на этот крутой пример от Скотта Толински. Смысл в том, что у нас есть список функций, уроков или чего-угодно другого, и мы хотим затенить этот текст, чтобы привлечь к нему внимание пользователя.
Вот смотрите:
![](https://habrastorage.org/webt/q5/wo/nu/q5wonunr46brwmzwieonaehf97s.png)
Здесь мы видим список, который к низу затухает. Для реализации этого эффекта идеально подходит CSS, поскольку позволяет смешивать текст с фоном, будь то изображение или просто тёмная подложка.
![](https://habrastorage.org/webt/w5/_w/bn/w5_wbnzxufb3xxzqej73nwqkhso.png)
Теперь посмотрим на градиентную маску, чтобы понять, как она работает.
![](https://habrastorage.org/webt/td/if/kj/tdifkjbfamjc1vetdnxovqtpzny.png)
В CSS это будет выглядеть так:
.list {
mask-image: linear-gradient(to bottom, #000, transparent 95%);
}
▍ Интересные эффекты для изображения
При использовании маскирования и градиентов наши возможности по созданию визуальных эффектов становятся практически безграничными. Ниже я приведу простой пример создания интересного эффекта для изображения.
Вот простой дизайн, который я сделал для этого демо.
![](https://habrastorage.org/webt/at/l9/3b/atl93beq3tu8ycsadsczhv4luj4.png)
Наблюдаемый эффект состоит из 5 линейных градиентов. Подобный результат можно получить, добавляя каждому из них разные позиции.
Взглянем на градиенты более детально:
.thumb {
mask-image: linear-gradient(to bottom, #000, #000),
linear-gradient(to bottom, #000, #000),
linear-gradient(to bottom, #000, #000),
linear-gradient(to bottom, #000, #000),
linear-gradient(to bottom, #000, #000);
mask-size: 18% 70%;
mask-position: 0 100%, 25% 25%, 50% 50%, 75% 0, 100% 50%;
mask-repeat: no-repeat;
}
Визуально маска выглядит так:
![](https://habrastorage.org/webt/ng/5d/76/ng5d767s1rpoyc26ol_loyd3if8.png)
Для создания эффекта затухания в каждом прямоугольнике маски нужно обновить градиент и добавить ключевое слово
transparent
..thumb {
mask-image: linear-gradient(to bottom, transparent, #000),
linear-gradient(to bottom, #000, transparent),
linear-gradient(to bottom, transparent, #000),
linear-gradient(to bottom, #000, transparent),
linear-gradient(to bottom, transparent, #000);
mask-size: 18% 70%;
mask-position: 0 100%, 25% 25%, 50% 50%, 75% 0, 100% 50%;
mask-repeat: no-repeat;
}
![](https://habrastorage.org/webt/wt/ds/i3/wtdsi3tgag6q-pqaihmzwwbvd4e.png)
▍ Скругление вкладок
Я также подумал о возможном применении масок к функционалу UI под названием «скругление углов» (round out corners).
Наша задача — скруглить стороны элемента так, чтобы они смешались с его
border-radius
.![](https://habrastorage.org/webt/sp/q_/_c/spq__cc2d5ibb_zihkjp9msjcny.png)
В своей статье Крис Койер объяснил, как можно достичь этого эффекта с помощью множества псевдо-элементов. Более же динамичным решением будет использование маски CSS.
Для начала повнимательнее взглянем на фигуру, которую нужно получить.
![](https://habrastorage.org/webt/xv/g0/nt/xvg0ntnzo1ivfeb3rj11-pg8exu.png)
Она состоит из квадрата и круга, и нам нужно их пересечение.
Как этого достичь? Можно использовать многослойные маски, объединив их с помощью свойства
mask-composite
.Первым делом мы создадим элемент для хранения самой маски.
.nav-item.active:before {
content: "";
position: absolute;
left: 100%;
bottom: 0;
width: 24px;
height: 24px;
background-color: var(--active-bg);
}
![](https://habrastorage.org/webt/eo/70/fj/eo70fju5hvcap7dbf_3h587irdc.png)
Внутри этого пространства нужно нарисовать круг и квадрат, которые будут совмещаться. Удобно то, что это можно сделать путём смешения линейного и радиального градиентов.
.nav-item.active:before {
content: "";
position: absolute;
left: 100%;
bottom: 0;
width: 24px;
height: 24px;
background-color: var(--active-bg);
background-image: linear-gradient(to top, #000, #000),
radial-gradient(circle 15px at center, #000 80%, transparent 81%);
background-size: 12px 12px, 100%;
background-position: bottom left, center;
background-repeat: no-repeat, repeat;
}
Обратите внимание на следующее:
- в качестве размера квадрата я установил 12px 12px;
- квадрат расположен в левом нижнем углу (bottom left);
- для фигуры квадрата
background-repeat
не требуется.
![](https://habrastorage.org/webt/ri/fy/c2/rifyc2spkzvonomb728lrrk_phu.png)
Картинка выше просто визуально показывает, как будут выглядеть два градиента. Следующим шагом идёт их создание. В CSS объединить две фигуры можно с помощью свойства
mask-composite
..nav-item.active:before {
content: "";
position: absolute;
left: 100%;
bottom: 0;
width: 24px;
height: 24px;
background-color: var(--active-bg);
mask-image: linear-gradient(to top, red, red),
radial-gradient(circle 15px at center, green 80%, transparent 81%);
mask-size: 12px 12px, 100%;
mask-position: bottom left, center;
mask-repeat: no-repeat, repeat;
mask-composite: subtract;
}
В итоге получится:
![](https://habrastorage.org/webt/pm/vn/9l/pmvn9lrqyh4u38sz4mful0e_wwc.png)
Код выше предназначен для фигуры справа. Для второй же стороны можно просто изменить
mask-position
..nav-item.active:after {
/* другие стили */
mask-position: bottom right, center;
}
Демо
▍ Вырезание нескольких аватарок
В своей статье (англ.), посвящённой эффекту вырезания, я рассказал о нескольких способах его реализации в CSS.
Один из приведённых там примеров хорошо подходит для маскирования.
![](https://habrastorage.org/webt/rc/kz/qx/rckzqx3sius3ozpks1nigxgdyco.png)
В этом случае можно получить такой эффект с помощью радиального градиента.
.avatar {
-webkit-mask-image: radial-gradient(ellipse 54px 135px at 11px center, #0000 30px, #000 0);
}
![](https://habrastorage.org/webt/mq/7f/ss/mq7fssweycexjyf8enbwldkjkk0.png)
Очень рекомендую ту статью, так как в ней есть много подробных примеров вроде приведённого выше.
Заключение
Когда я начал собирать дополнительную информацию по маскированию в CSS, то оказалось, что по этой теме доступно не так много ресурсов. Причём среди них явно недостаёт практических примеров, которые можно было бы применить в повседневном рабочем процессе. Надеюсь, что к концу этой статьи вы уже представили себе, где в своём следующем проекте сможете задействовать маскирование.
Дополнительные ресурсы
Если вы хотите отточить навыки на дополнительных примерах, то рекомендую следующие материалы:
- A Fancy Hover Effect For Your Avatar от Temani Afif
- Mask Compositing: The Crash Course Ana Tudor
- CSS only Speech Bubble Temani Afif
- Fancy gradient border on hover от Temani Afif
Благодарю за чтение!
Telegram-канал с розыгрышами призов, новостями IT и постами о ретроиграх ????️
![](https://habrastorage.org/webt/_p/_h/lv/_p_hlvd2tv0cv9tny8tdytzfhje.png)
Karlen-ll
Спасибо.
Подмечу только, что inset имеет хорошую поддержку, но это еще экспериментальное свойство... поэтому, с ним поаккуратнее ????