В некоторых дизайнах иногда попадаются моменты, когда к определённому элементу необходимо применить эффект вырезания. Есть несколько способов добиться такого эффекта, используя CSS или SVG, но у каждого из них есть свои плюсы и минусы. Попробуем рассмотреть их на конкретной ситуации.
Введение
Во-первых, давайте определимся, что имеется в виду под эффектом вырезания. Речь идет о вырезании части фигуры. Вот пример:
У нас есть элемент 1 - круг и элемент 2 - прямоугольник. Необходимо из элемента 2 вырезать 1. В дизайнерских графических редакторах это просто сделать. Однако когда дело доходит до реализации аналогичных эффектов на уровне вёрстки, это может быть немного сложней по разным причинам:
- Может потребоваться JavaScript для переключений режимов вырезанного/не вырезанного элемента
- Элемент может содержать изображение или текст
- Добавление рамки или теней может усложнить задачу
Давайте рассмотрим конкретный пример и то, как мы можем реализовать в нем эффект вырезания с помощью CSS или SVG.
Вырезание аватарки
Представим, дизайнером отрисован такой элемент - аватарка со статусом. Статус - кружок в нижнем правом углу, который может быть разного цвета в зависимости от состояния: зелёный (в сети), красный (недоступен) и т.д.
Как мы можем застилить статус? Мы можем добавить белую рамку или тень к зеленому кружку и положить этому конец, верно? Однако, здесь дело обстоит не так. С тёмным фоном это будет выглядеть так:
Опять же, можно просто изменить обводку значка в соответствии с фоном, но это не лучшее решение. Давайте посмотрим, как это можно сделать элегантнее.
Способ 1 - Clip Path
В этом решении используется сочетание SVG и CSS. Во-первых, нам нужно создать path и экспортировать его как SVG. Вы можете сделать это в любом редакторе, работающем с вектором (Adobe Illustrator, Figma, ...), и экспортировать его как SVG. По сути, нам нужна вот такая SVG:
Когда мы сделали эту SVG, нам нужно скопировать значение path и преобразовать их в относительные единицы. По умолчанию точки пути в SVG являются абсолютными. Это означает, что они могут растягиваться при изменении ширины и высоты. Чтобы исправить это на раннем этапе, используем этот отличный инструмент.
Затем, инлайново на странице добавляем SVG с уже исправленным clipPath.
<svg class="svg">
<clipPath id="circle" clipPathUnits="objectBoundingBox">
<path d="M0.5,0 C0.776,0,1,0.224,1,0.5 C1,0.603,0.969,0.7,0.915,0.779 C0.897,0.767,0.876,0.76,0.853,0.76 C0.794,0.76,0.747,0.808,0.747,0.867 C0.747,0.888,0.753,0.908,0.764,0.925 C0.687,0.972,0.597,1,0.5,1 C0.224,1,0,0.776,0,0.5 C0,0.224,0.224,0,0.5,0">
</path>
</clipPath>
</svg>
Значение objectBoundingBox для атрибута clipPathUnits означает, что значения внутри path относятся к ограничивающей рамке элемента, к которому применяется clip-path.
Самой картинке собственно добавляем свойство clip-path:
img {
clip-path: url("#circle");
}
Плюсы такого способа:
- Кроссбраузерность, работает во всех основных версиях Chrome, Edge, Firefox и Safari;
- Подходит для очень простых примеров. В сочетании с границами или тенями могут быть трудности.
Минусы:
- Чтобы изменить вырез, нужно изменить path. Это может вызвать осложнения, если отрисованы статусы с разными вырезаниями;
- Требуется некоторый опыт работы со слияниями фигур в графических редакторах.
Способ 2 - CSS-маска
Эффект вырезания можно создать, используя комбинацию CSS-маски и градиентов. Давайте посмотрим, как это сделать.
Используя радиальный градиент radial-gradient, мы можем нарисовать круг, а затем заполнить остальное пространство другим цветом. Рассмотрим следующий рисунок:
Чтоб его заверстать градиентом, мы можем прописать следующее:
.image {
background-image: radial-gradient(circle 20px at calc(100% - 25px) calc(100% - 25px), yellow 30px, deepskyblue 0);
/* yellow - желтый цвет, deepskyblue - голубой */
}
А чтобы воссоздать подобие аватарки, изменим цвета и добавим радиус:
.image {
background-image: radial-gradient(circle 20px at calc(100% - 25px) calc(100% - 25px), transparent 30px, deepskyblue 0);
border-radius: 50%;
}
Основываясь на этих возможностях, мы можем применить CSS-маску к картинке:
img {
-webkit-mask-image: radial-gradient(circle 20px at calc(100% - 25px) calc(100% - 25px), transparent 30px, deepskyblue 0);
border-radius: 50%;
}
Плюсы такого способа:
- Кроссбраузерность, но с вендорным префиксом для всех браузеров, кроме Firefox.
Минусы:
- Может быть ограниченным или сложным в исполнении для других дизайнов.
Способ 3 - SVG-маска
Для начала, давайте рассмотрим, как работает SVG-маска. Нам нужно создать маску, а затем применить ее где-нибудь внутри самого SVG.
В качестве примера, попробуем обрезать нашу аватарку просто круглой маской. Для этого достаточно в код добавить такую SVG:
<svg class="img">
<mask id="circle">
<circle fill="white" cx="100" cy="100" r="100"></circle>
</mask>
<g mask="url(#circle)">
<image x="0" y="0" height="100%" preserveAspectRatio="xMidYMid slice" width="100%" xlink:href="avatar.jpg"></image>
</g>
</svg>
Как видим, синтаксически SVG-маска отличается от CSS-маски. Проанализируем код:
- Во-первых, у нас появился элемент <mask>, содержащий круг <circle>;
- Маска применяется к элементу <image>. В SVG это может быть что угодно, например, тег <g>.
На выходе получим:
Давайте добавим второй кружочек к маске:
<svg class="img">
<mask id="circle">
<circle fill="white" cx="100" cy="100" r="100"></circle>
<circle fill="white" cx="86%" cy="86%" r="18"></circle>
</mask>
<g mask="url(#circle)">
<image x="0" y="0" height="100%" preserveAspectRatio="xMidYMid slice" width="100%" xlink:href="avatar.jpg"></image>
</g>
</svg>
Однако на выходе получим:
Как же нам добиться эффекта вырезания второго круга? Интересная вещь - в масках объект с белой заливкой представляет область, которую мы хотим показать, а объект, залитый черным, представляет собой область, которую мы хотим скрыть.
Давайте вместо этого изменим заливку маленького кружка на черный:
<svg class="img">
<mask id="circle">
<circle fill="white" cx="100" cy="100" r="100"></circle>
<circle fill="black" cx="86%" cy="86%" r="18"></circle>
</mask>
<g mask="url(#circle)">
<image x="0" y="0" height="100%" preserveAspectRatio="xMidYMid slice" width="100%" xlink:href="avatar.jpg"></image>
</g>
</svg>
Когда оба элемента маски белые, это приведет к результату, подобному объединению двух фигур. Если один белый, а другой черный, одна фигура будет вычитаться из другой.
Теперь результат будет таким:
Плюсы такого способа:
- Простое решение;
- Отличная кроссбраузерная поддержка;
- Код легко поддерживать.
Минусы:
- Субъективно, у этого решения нет никаких минусов, кроме того, что это может быть немного сложно для человека, который не знает SVG.
Способ 3 является лучшим решением. К сведению, им пользуется Facebook. Если это нам что-то говорит, так это то, что это решение работает во всех браузерах без проблем, а также позволяет отключить маску, когда она не нужна.
Комментарии (1)