Что такое CSS маски и зачем они нужны
Хорошая новость заключается в том, что CSS маскирование будет частью Interop 2023, а это значит, что мы должны ожидать кросс-браузерной поддержки (Ура!!).
В этой статье я расскажу, что такое CSS маскирование, как оно работает, а также несколько вариантов его использования и примеры.
- Что такое маскирование
- Как маскировать в CSS
- Маскирование с помощью CSS градиентов
- Практические варианты использования и примеры
- Заключение
- Дополнительные ресурсы
Что такое маскирование
Проще говоря, маскирование работает таким образом, что скрывает часть элемента, не стирая его.
Рассмотрим следующий рисунок:

У нас есть изображение и есть маска. В дизайнерских приложениях, таких как Photoshop, мы можем вставить изображение внутри серой фигуры, и это приведёт к маскированию изображения.
Способ, который работает, заключается в том, что он скрывает некоторые части изображения, не стирая его (они всё ещё там, но скрыты).

Это основная концепция маскирования, заключающаяся в использовании фигуры для отображения и сокрытия частей элемента. Мы можем пойти дальше и исследовать ещё более уникальные способы маскирования контента.
Например, мы можем создать градиентную маску, как показано ниже.

В градиенте есть заполненные и прозрачные пиксели. Заполненные — там, где будет видна часть элемента, а прозрачные — там, где скрытые части.

В Photoshop мы можем добавить маску слоя к группе слоёв, и содержимое этой группы будет замаскировано внутри неё. Этот способ работает с помощью инструмента Кисть
, чтобы скрыть часть группы, и она будет замаскирована.

Содержимое, которое замаскировано, не стирается, оно просто скрывается (обратите внимание на элементы группы).
Ладно, хватит теории. В следующих разделах я рассмотрю способы маскирования CSS.
Как маскировать в CSS
В CSS есть несколько способов маскировать элементы:
- Свойство
mask
. - Свойство
clip-path
. - SVG
<mask>
.
Основное различие между свойством mask
и clip-path
заключается в том, что первое используется для изображений и градиентов, а второе для путей. В этой статье основное внимание будет уделено свойству mask
.
В CSS у нас есть сокращённое свойство mask
, аналогичная свойству background
. Да, вы правильно прочитали. Вот почему я думаю, что синтаксис легко запомнить, потому что он буквально такой же, как свойство background
, но с несколькими дополнительными свойствами.
Вместо того чтобы перечислять все свойства CSS маски, я приведу пример, в котором функции маски постепенно будут расширяться, чтобы вы могли заметить разницу.
CSS background
выглядит так:
.card__thumb {
background-image: url('hero-cool.png');
}
… а CSS mask
выглядит так:
.card__thumb {
mask-image: url('hero-cool.png');
}
Это круто, правда? Это значительно облегчит понимание и запоминание CSS масок.
Давайте переделаем первоначальный пример с помощью CSS.
Во-первых, мне нужно экспортировать фигуру как png
изображение.

Предположим, я хочу применить маску к изображению.
<img src="ahmad-shadeed-web-directions.jpg" alt="" />
img {
mask-image: url("shape.png");
}
Можете ли вы ожидать такой результат? По умолчанию маска будет повторяться, а её размер будет равен самому изображению маски. В настоящее время результат выглядит следующим образом:

Чтобы изменить это, нужно установить mask-repeat
в no-repeat
, как и фоновые изображения CSS.
img {
mask-image: url("shape.png");
mask-repeat: no-repeat;
}

Потрясающе! Обратите внимание, что маска расположена в левом верхнем углу. Мы можем изменить это с помощью mask-position
. Обратите внимание, синтаксис идентичен background-images
!
img {
mask-image: url("shape.png");
mask-repeat: no-repeat;
mask-position: center;
}

Помимо положения, мы также можем изменить размер маски. Это полезно для создания маски изображения реагирующей на размер элемента.
img {
mask-image: url("shape.png");
mask-repeat: no-repeat;
mask-position: center;
mask-size: 60%;
}

Есть ещё несколько свойств маски, но я не хочу перегружать вас ими сейчас. Мы вернёмся к ним позже, с реальными вариантами использования.
Маскирование с помощью CSS градиентов
CSS маскирование — это не только использование изображения, также можно использовать градиенты для создания мощных и полезных эффектов маскирования.
Позже я покажу несколько полезных вариантов использования, но сейчас я хочу сосредоточиться на основных принципах работы градиентов с маскированием.
В следующем примере mas-image
содержит линейный CSS градиент от полностью чёрного до прозрачного.
img {
mask-image: linear-gradient(#000, transparent);
}

Согласно MDN
По умолчанию это означает, что альфа-канал изображения маски будет умножен на альфа-канал элемента. Это можно контролировать с помощью свойства
mask-mode
.
Это означает, что вы можете использовать любой цвет кроме чёрного, и маска всё равно будет работать, потому что режим маскирования по умолчанию установлена на alpha
(позже мы рассмотрим это подробнее).
img {
mask-image: linear-gradient(red, transparent);
}

Опять, концепция маскировки заключается в том, что прозрачный пиксель будет скрыт. Вот упрощённый пример градиента с жёсткими цветовыми стоп точками:
img {
mask-image: linear-gradient(#000 50%, transparent 0);
}

Круто! Теперь, когда основные концепции маскирования ясны (надеюсь, на это), давайте рассмотрим несколько практических вариантов использования CSS масок.
Практические варианты использования и примеры
Исчезновение изображения
Интересное использование маскирования — это когда мы хотим затемнить изображение и заставить его сливаться с фоном под ним.
Рассмотрим следующее изображение:

На первый взгляд может показаться, что нужно добавить градиент того же цвета, что и фон. Что-то вроде этого:
.hero__thumb:after {
position: absolute;
inset: 0;
background: linear-gradient(to top, #f1f1f1, transparent)
}
Хотя это может работать, это не сработает при изменении основного цвета фона. Обратите внимание, что у главного изображения теперь жёсткие цветовые стоп точки:

С помощью CSS маскирования можно замаскировать главное изображение и заставить его работать с любым цветом фона.
.hero__thumb {
mask-image: linear-gradient(#000, transparent);
}
Вот и всё! Теперь эффект затухания реален и не подведёт при изменении фона главной страницы. Смотри следующий пример:

Маскирование текстового содержимого: Пример 1
Когда мы хотим отобразить длинный текст, но места недостаточно, чтобы отобразить его полностью, решением будет затухание текста как в начале, таки в конце. Затем текст будет анимироваться в любом направлении, чтобы показать оставшееся содержимое.
Рассмотрим следующий рисунок:

Использование хака с градиентом не сработает, потому что фон под содержимым изменится. Это может быть сплошной цвет или изображение.

Чтобы реализовать это в CSS, нужно добавить маску градиента, затемняющую содержимое в начале и в конце.
Мне нравиться сначала делать в CSS градиенте и видеть результат, а затем применять его как маску. Это помогает визуализировать градиент перед использованием его в качестве маски.
.c-card__footer {
background-image: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent 100%);
}

Имея на руках всё выше перечисленное, мы можем применить его как маску.
.c-card__footer {
mask-image: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent 100%);
}
Всё ещё не идеально? Мы можем возиться со значениями градиента, пока результат не станет идеальным.
Маскирование текстового содержимого: Пример 2
Это то же самое, что и предыдущий пример, но применяется вертикально. Я видел это в live video в Instagram.
Рассмотрим следующее изображение:

Заметили как контент размывается вверху? В этом маленьком месте могут быть комментарии ленты, экшены и другие вещи. Использование CSS маски идеально подходит для этого.
Во-первых, давайте посмотрим на градиент.

В CSS это может быть реализовано примерно так:
.whatever-the-class-name {
mask-image: linear-gradient(to bottom, transparent, #000);
}
Маскирование списков
Я видел этот классный пример Скотта Толински, когда проводил исследование CSS масок. Идея в том, что у нас есть список возможностей, уроков или чего-то ещё. Мы хотим скрывать текст, чтобы больше заинтересовать пользователя тем, что там находится.
Рассмотрим следующий пример:

Как вы видите слева, у нас есть список, а в самом низу он затемнён. Использование CSS маскирования для этого подходит идеально, так как оно может сливаться с нижним фоном, будь то изображение или тёмный фон.

Давайте посмотрим на градиент маски, чтобы понять, как он работает.

В CSS это выглядит так:
.list {
mask-image: linear-gradient(to bottom, #000, transparent 95%);
}
Интересные эффекты изображения
С CSS масками и градиентами возможности создания визуальных эффектов безграничны. Это простой пример того, как мы можем создать визуальный эффект для изображения.
Этот быстрый дизайн я сделал для этой демонстрации.

Эффект изображения, который вы видите, состоит из пяти линейных градиентов. Добавляя разные позиции для каждой из них, мы можем сделать что-то похожее.
Рассмотрим градиент по ближе:
.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;
}
Визуально маска выглядит так:

Для создания эффекта затухания на каждом прямоугольнике маски, нужно обновить каждый градиент и добавить ключевое слово 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;
}

Также можно анимировать размер или позицию маски при наведении курсора.
Это мощно. Представьте, что вы сочетаете это с анимацией на основе прокрутки страницы. Ситуация может выйти из-под контроля (в хорошем смысле).
Закруглённые вкладки
Я подумал о том, чтобы попробовать CSS маски для улучшения пользовательского интерфейса под названием Закругление углов
Идея состоит в том, что мы хотим закруглить стороны элемента таким образом, чтобы он сочетался с border-radius
, которые есть у элемента.

В статье Chris Coyier объяснил, как добиться этого с помощью нескольких псевдо элементов. Более динамичным решением было бы использование CSS маски.
Давайте рассмотрим форму, которую я хочу получить.

Фигура состоит из квадрата и круга. Нам нужно их пересечение.
Как этого добиться? Мы можем использовать многослойные маски вместе со свойством mask-composition
для выполнения над ними операции компоновки.
Сначала, нужно создать элемент для хранения маски.
.nav-item.active:before {
content: "";
position: absolute;
left: 100%;
bottom: 0;
width: 24px;
height: 24px;
background-color: var(--active-bg);
}

В этом пространстве нужно нарисовать круг и квадрат, чтобы скомпоновать их. К счастью, мы можем сделать это, смешав линейный и радиальный градиенты.
.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
не требуется для квадратной формы.

Данное изображение приведено для визуальной демонстрации того, как будут выглядеть два градиента. Следующий шаг — сделать их! В 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;
}
Вот результат вышеизложенного:

Выше был CSS код для фигуры справа от вкладки. Для другой стороны мы можем просто изменить mask-position
, и она перевернётся.
.nav-item.active:after {
/* other styles */
mask-position: bottom right, center;
}
Готовый пример на CodePen:
Вырезание нескольких аватаров
В своей статье об эффекте вырезания я исследовал различные способы создания выреза в CSS.
Один из примеров хорош для CSS маскирования.

С CSS маскированием мы можем использовать радиальный градиент для достижения этого эффекта.
.avatar {
-webkit-mask-image: radial-gradient(ellipse 54px 135px at 11px center, #0000 30px, #000 0);
}

Настоятельно рекомендую прочитать статью, так как в ней есть множество примеров, подобных этому.
Заключение
Когда я начал больше изучать маскирование в CSS, ресурсы были ограничены. Что ещё более важно, было очень мало практических вариантов использования, которые мы могли бы использовать в нашем повседневном рабочем процессе. Я надеюсь, что к концу этой статьи у вас появится представление о том, где использовать CSS маскирование в вашем следующем проекте.
Я не стал углубляться в свойства типа mask-mode
, потому что, честно говоря, не нашёл проблем для решения с ними (до сих пор). Я обновлю статью, когда у меня будет убедительный пример использования такого свойства.
Дополнительные ресурс
Если вы хотите отточить свои навыки в ещё большем количестве примеров CSS маскирования, вам необходимо взглянуть на следующее:
- A Fancy Hover Effect For Your Avatar by Temani Afif
- Mask Compositing: The Crash Course by Ana Tudor
- CSS only Speech Bubble by Temani Afif
- Fancy gradient border on hover by Temani Afif