Отсечение и маскирование уже давно присутствуют в CSS и даже имеют довольно приличную поддержку браузером. Недавно я работал над проектом, в котором требовалось использовать технику вырезания для всплывающих подсказок, показывающих ссылки выше в тексте.
Эти всплывающие подсказки имеют два вида в зависимости от их содержания:
Вы могли подумать, что всплывающая подсказка к тексту вообще не требует отсечения. Псевдоэлемент можно расположить внизу, чтобы добавить небольшую выемку, верно? Вы действительно абсолютно правы! Поскольку фон всплывающей подсказки имеет однотонный цвет, нет никакой необходимости в хитростях CSS и тому подобном.
Но отсечение изображения во втором дизайне — вот где все становится интереснее…
Вот мыслительный процесс, которым следовал мой разум, когда я приступил к выполнению задания.
Содержание статьи
Идея 1: траектория и многоугольник
Свойство CSS clip-path
позволяет нам определять настраиваемый многоугольник с процентными значениями для создания нужного пути.
Этого решения часто бывает достаточно, если форма вашего пути достаточно проста. В демонстрации ниже я использую значения calc ()
чтобы убедиться, что клип полностью реагирует, в то время как маленький треугольник остается того же размера независимо от того, насколько растянут родительский элемент.
.tooltip {
клип-путь: многоугольник (
0% 0%, // Левая верхняя точка
100% 0%, // правая верхняя точка
100% calc (100% - 10px), // Нижняя правая точка
calc (50% + 10px) calc (100% - 10px), // Центр справа треугольника
50% 100%, // Кончик треугольника
calc (50% - 10px) calc (100% - 10px), // Центр слева от треугольника
0% calc (100% - 10px) // Нижняя левая точка
);
}
Это решение очень чистое, но в моем случае недостаточно хорошее, так как у меня нет прямого треугольного паза, а скорее нестандартная форма.
Идея 2: клип-путь и SVG
Использование пути SVG казалось хорошим решением. Сначала вы экспортируете свой путь обрезки SVG, а затем используете его в своем CSS со значением url (#clipPathId)
.
Посмотрите демо ниже. Видите ли вы какие-нибудь проблемы с путем?
Стрелка растягивается в зависимости от соотношения сторон изображения. Так как небольшая выемка является частью всей формы пути, она растягивается по размеру прямоугольной части пути.
Идея 3: маска-изображение
Вот то, что я обнаружил с помощью свойства CSS mask-image
в CSS: вы можете комбинировать слои маски! Думайте об этом как о фоновом изображении
в CSS. Вы можете применить несколько градиентов или изображений к одному элементу. Что, если вы объедините все эти слои, чтобы создать окончательную маску, которая вам нужна?
Это именно то, что мы собираемся сделать здесь с двумя слоями:
- Большой прямоугольник, покрывающий весь блок, за исключением полосы внизу (показано зеленым)
- Изображение стрелки (показано розовым)
При таком решении прямоугольник может растягиваться в соответствии с размерами всплывающей подсказки, а стрелка всегда будет сохранять свой фиксированный размер.
Весь приведенный ниже код и демонстрации не содержат префиксов, а демонстрации используют Autoprefixer. На момент написания этой статьи для Edge, Chrome и Safari требуются префиксы.
Как и в случае со свойствами фона, мы собираемся использовать три различных свойства маски для определения наших двух слоев:
-
маска-изображение
: это свойство позволяет нам рисовать прямоугольник с линейным фоном и стрелку со встроенным SVG. -
положение маски
: Прямоугольник не требует позиции (так как он начинается в верхнем левом углу), но стрелка должна быть расположена в центре внизу. -
повтор маски
: Мы нужно избегать повторения обоих слоев; в противном случае линейный градиент при повторении будет охватывать весь элемент.
.tooltip {
маска-изображение:
линейный градиент (#fff, #fff), / * Прямоугольник * /
url ('данные: изображение / svg + xml; utf8,'); / * Положение маски нижней стрелки: * /
0 0, / * прямоугольник * /
50% 100%; / * Нижняя стрелка * /
размер маски:
100% calc (100% - 18px), / * прямоугольник * /
38px 18px; / * Нижняя стрелка * /
маска-повтор: без повторения;
}
Тада! Измените размеры всплывающей подсказки или замените изображение, и нижняя стрелка сохранит исходное соотношение.
Более сложные формы
Давайте немного пофантазируем и углубимся в эту технику. Меня вдохновило приложение iMessage для iOS, и я попытался воспроизвести те же всплывающие подсказки с помощью этой техники маскирования.
Мне пришлось нарисовать больше слоев, чтобы моя маска отображала каждый закругленный угол:
- четыре круга, по одному для каждого угла (показаны красным)
- один горизонтальный прямоугольник (показан синим)
- один вертикальный прямоугольник (показан зеленым)
- один SVG для стрелки (показан желтым)
Полный код будет немного длиннее, так как у нас будет больше слоев для рисования, но логика останется прежней. Углы нарисованы с использованием четырех радиальных градиентов. Чтобы заполнить прямоугольник, нам понадобятся два прямоугольника (один вертикальный, один горизонтальный), как показано выше. И, наконец, наша маленькая стрелка, которая использует встроенный SVG.
.tooltip {
- радиус: 25 пикселей;
маска-изображение:
radial-gradient (#fff (var (- radius) - 1), # fff0 var (- radius)), / * Верхний левый угол * /
radial-gradient (#fff (var (- radius) - 1), # fff0 var (- radius)), / * Правый верхний угол * /
radial-gradient (#fff (var (- radius) - 1), # fff0 var (- radius)), / * нижний левый угол * /
radial-gradient (#fff (var (- radius) - 1), # fff0 var (- radius)), / * нижний правый угол * /
linear-gradient (#fff, #fff), / * Горизонтальный градиент * /
linear-gradient (#fff, #fff), / * Вертикальный градиент * /
url ('данные: изображение / svg + xml; utf8,'); / * Значок внизу справа * /
положение маски:
0 0, / * Верхний левый угол * /
100% 0, / * Правый верхний угол * /
0 100%, / * нижний левый угол * /
100% 100%, / * нижний правый угол * /
0 var (- radius), / * Горизонтальный градиент * /
var (- radius) 0, / * Вертикальный градиент * /
100% 100%; / * Значок внизу справа * /
размер маски:
(var (- radius) * 2) (var (- radius) * 2), / * Верхний левый угол * /
(var (- radius) * 2) (var (- radius) * 2), / * Правый верхний угол * /
(var (- radius) * 2) (var (- radius) * 2), / * нижний левый угол * /
(var (- radius) * 2) (var (- radius) * 2), / * нижний правый угол * /
100% calc (100% - # {var (- radius) * 2}), / * Горизонтальный градиент * /
calc (100% - # {var (- radius) * 2}) 100%, / * Вертикальный градиент * /
(39 пикселей / 2) (25 пикселей / 2); / * Значок внизу справа * /
маска-повтор: без повторения;
}
Как видите, мы можем создать версию со стрелкой влево или вправо, используя перевернутую версию стрелки и расположив ее в другом углу. Трюк отлично работает и с всплывающими подсказками без изображений. Но, как я сказал в начале этой статьи, вам, вероятно, не понадобится столько CSS, если у вас есть только простой фон для стилизации.
Если вы хотите узнать больше об отсечении и маскировании в CSS, есть много других замечательных статей о CSS-приемах, которые стоит проверить.