Использование CSS-масок для создания зубчатых краев
Я работал над проектом, который имел этот аккуратный зазубренный край вдоль нижней части изображения баннера.
Это то, что заставило меня задуматься на секунду и я кое-что узнал в процессе! Я решил написать, как я пришел к этому, чтобы вы могли использовать мой опыт в своих собственных проектах.
Я начал со старого доброго HTML-изображения в элементе оболочки:
<div class="jagged-wrapper">
<img src="path-to-image.jpg" />
</div>
Затем я использовал псевдоэлемент ::after
, чтобы добавить на него повторяющееся фоновое изображение:
.jagged-wrapper::after {
content: "";
background-image: url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" preserveAspectRatio="none"><polygon style="fill:white;" points="1,0 1,1 0,1 "/></svg>');
background-size: 30px 30px;
width: 100%;
height: 30px;
position: absolute;
bottom: 0px;
right: 0;
z-index: 2;
}
Это код SVG, преобразованный в URI данных.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" preserveAspectRatio="none">
<polygon style="fill: white;" points="1,0 1,1 0,1 "/>
</svg>
"Вот и оно!"
Хотя это конечно работает, но доставляет много хлопот. Трудно читать разметку SVG в CSS таким образом. Кроме того, раздражает необходимость не забывать цитировать их (например, url('data:image/svg+xml'...)
). Конечно, мы можем кодировать SVG на base64, чтобы избежать этого, но это еще более раздражает. Кроме того SVG должен быть заполнен тем же цветом фона, что и изображение (или где бы оно ни использовалось), иначе он не будет работать.
Подождите, а разве не для этого нужна маскировка? Да! Да, именно для этого и существует маскировка.
Это привело меня к новому подходу: использовать изображение, подобное приведенному выше, в качестве CSS-маски, чтобы “отсутствующие " биты изображения баннера, действительно отсутствовали. Вместо того, чтобы рисовать треугольники цвета фона поверх баннера, мы должны полностью замаскировать эти треугольники от баннера и пропустить реальный фон. Таким образом это работает на любом фоне!
Маскирование в значительной степени поддерживается везде - по крайней мере, простым способом, о котором я говорю здесь. Мы также говорим о чем-то, что может быть реализовано с прогрессивным улучшением. Если маски не поддерживаются в данном браузере, то вы просто не получите "пилообразный" эффект.
Одним из способов работы маски CSS является предоставление изображения с альфа-каналом в виде mask-image
. Базовый элемент, маскируемый, становится полупрозрачным в той степени, в которой mask-image
диктует альфа-канал. Таким образом, если изображение маски представляет собой белый чайник на прозрачном фоне, маскированный элемент будет обрезан по форме чайника, и все, что снаружи, будет скрыто.
Нам нужно одно "пилообразное" изображение, похожее на SVG выше, где верхняя левая половина заполнена белым, а нижняя левая половина полупрозрачной. В идеале это изображение не было бы настоящим SVG, поскольку это вернуло бы нас в ужасный беспорядок URI данных, в котором мы были прежде.
В этот момент вы можете подумать: "Эй, просто вставьте SVG непосредственно в CSS, определите маску в нем, а затем укажите CSS на идентификатор маски в SVG!"
Хорошая идея! И это безусловно выполнимо, если вы можете редактировать HTML. Однако для моего конкретного проекта я работал в WordPress и я действительно хотел ограничить свои изменения чистым CSS, а не вставлять дополнительные части в HTML. Это было бы намного больше работы. Я не думаю что это необычно, для такого изменения презентации полезно не редактировать HTML. Мы в основном придерживаемся идеи избегать семантически бесполезных элементов-обёрток только для того, чтобы обеспечить привязки к стилю, но я чувствую, что это также относится к добавлению всей разметки SVG к документу или даже шаблону WordPress.
Вместо этого мы можем использовать линейный градиент CSS, чтобы создать форму треугольника:
.el {
linear-gradient(
to bottom right,
white,
white 50%,
transparent 50%,
transparent
);
}
Вот оно на радиальном фоне, так что вы можете видеть что он действительно прозрачный:
Отлично! Мы можем просто использовать это как mask-image
на нашем баннере? Нужно установить mask-size
, что как background-size
, и mask-repeat
, как background-repeat
и готово?
К сожалению нет. Не так хорошо, как хотелось бы.
Первая причина в том, что, если вы не используете Firefox, вы скорее всего не увидите никакой маскировки в этом примере выше. Это связано с тем, что Blink и WebKit все еще поддерживают маскирование только с префиксом поставщика, на момент написания. Это означает, что нам нужны префиксные -webkit-
версии.
Помимо префиксов поставщиков, то что мы делаем, также концептуально неправильно. Если мы ограничим маску только нижней полосой изображения mask-size
, то у остальной части изображения вообще не будет mask-image
, что полностью ее маскирует. В результате мы не можем использовать "пилообраз" в качестве маски. Нам нужен прямоугольник mask-image
размером с изображение, с "пилообразным" концом внизу.
Что-то вроде этого:
Мы делаем это с двумя градиентными изображениями. Первое изображение - это тот же "пилообразный" треугольник что и выше, который установлен repeat-x
и расположен bottom
так, что повторяется только вдоль нижнего края изображения. Второе изображение - это еще один градиент, прозрачный для нижних 30 пикселей (чтобы не мешать "пилообразному"), непрозрачный над этим (который в демонстрации показан переходом от черного к белому) и занимающий весь размер элемента.
Итак, теперь у нас есть этот клинообразный кусок с одним треугольным "пилообразным" дном в нижней части и он занимает всю высоту нашего изображения баннера двумя отдельными частями. Наконец, мы можем использовать эти фрагменты mask-image
, повторяя их горизонтально на нашем изображении и это должно иметь желаемый эффект:
И вот оно у нас!