Вырезы 2.0 — рамки в форме вырезов | CSS Боль
В предыдущей части мы разобрали, как CSS-маски радикально упростили процесс вёрстки блоков с базовыми геометрическими вырезами — кругами, скосами и угловыми формами. В этой части изучим, как добавить к таким блокам рамки, повторяющие форму вырезов.
Давайте снова насладимся простотой создания вырезов. Перед вами блок с круглым вырезом, который сделан с помощью CSS-маски на основе одного радиального градиента.
Видеоверсия этого курса доступна во ВКонтакте и на Ютюбе
Следующий элемент в нашей коллекции — это блок со скосом, который создан с помощью маски из линейного градиента.
Угловой вырез создается с помощью одной маски и одного конического градиента.
Более интересный угловой вырез. Снова одна маска и один конический градиент.
Рассмотрим этот вырез, чтобы понять, как работают рамки. Сначала разберём, как устроена маска.
Временно заменим маску на фоновое изображение.
Приведем конический градиент к максимально простому виду. Это градиент с резким переходом между чёрным и прозрачным цветом на 20 градусах. Центр градиента совпадает с центром контейнера, а начальный угол равен нулю.
Увеличим угол резкого перехода.
Переместим центр градиента влево.
И увеличим начальный угол до 10 градусов.
Добавим зазор в полградуса между позициями смежных цветов, чтобы переход стал более плавным.
Добавим ещё два колорстопа, чтобы сгладить переход между последним и первым цветом градиента.
Попереключайте шаги вперед и назад, чтобы увидеть эффект сглаживания.
Маска полностью готова. Осталось только заменить background-image обратно на mask-image.
Подключим маску, и вырез появится. Теперь можем перейти к созданию рамок.
Если задать рамку для блока с маской, часть рамки обрежется. Если дизайнер считает это приемлемым, можно оставить так и не читать дальше.
Однако чаще всего этого бывает недостаточно.
Можно попробовать добавить тень с помощью box-shadow, но тень не будет видна.
Это связано с особенностью масок: они обрезают всё, что выходит за их пределы, включая тени.
Начнём исправлять ситуацию.
Типовое решение для блоков с масками — создание дополнительной обёртки. Зададим ей класс card-wrapper.
Перенесём размеры на обёртку, чтобы ширина блока .card зависела от ширины обёртки.
«Чиним» тень. Для этого добавим тень на обёртку с помощью фильтра drop-shadow.
Фильтр работает на блоке без маски, поэтому его не обрезает. Также он воспроизводит форму непрозрачных областей внутри элемента. Таким образом, он идеально подходит для блоков с вырезами.
Починить рамку сложнее. Поэтому сначала подготовимся. Скроем всё содержимое карточки, используем свойство visibility: hidden, и сделаем фон карточки полупрозрачным.
Теперь добавим обёртке так называемую «абсолютную подложку». Это псевдоэлемент с абсолютным позиционированием, размеры которого зависят от размеров обёртки.
Псевдоэлемент получит свойство inset со значением 10px и чёрный фон, чтобы его было хорошо видно.
Зададим псевдоэлементу z-index: -1, чтобы он всегда находился под карточкой .card.
Если указать для inset отрицательное значение, то абсолютная подложка увеличится по размерам обёртки на это значение, равномерно во всех направлениях.
Кстати, inset — это сокращённое свойство, которое задаёт значения для свойств top, left, right и bottom.
Абсолютная подложка удобна тем, что всегда сохраняет привязку к размерам обёртки.
Если добавить текст в карточку .card, её высота увеличится, и это повлияет на высоту обёртки .card-wrapper. Ведь и карточка, и обёртка находятся в потоке.
Вместе с изменением высоты обёртки изменится и высота подложки.
Вернём в карточку предыдущий текст и начнём работу над рамкой.
Перед вами чёрный прямоугольник, на котором расположена полупрозрачная карточка с вырезом. Форма выреза хорошо видна на фоне подложки.
Чтобы создать обводку, скопируем маску из карточки и добавим её на абсолютную подложку. Поскольку подложка больше карточки (из-за отрицательного inset), маска подложки будет смещена.
Мы создали «рамку», которая повторяет форму выреза, но её ширина неравномерна. Сделать ширину всех частей «рамки» одинаковой — это самая сложная задача. Давайте разберёмся, как её решить.
Временно отключим маску у подложки, чтобы увидеть весь прямоугольник.
Если задать inset-свойствам разные значения, подложка увеличится неравномерно в разных направлениях.
Например, если увеличить значения top и left, подложка станет больше слева и сверху. Это, в свою очередь, сместит маску, так как координаты центра конического градиента, который используется для создания маски, отсчитываются от верхнего левого угла блока.
Вернём маску обратно. Хорошо видно, что наклонные части рамки стали толще.
Изменяя значения inset-свойств, мы можем точно и гибко контролировать толщину наклонных частей рамки.
Мы решили проблему с наклонными частями, но появилась новая — увеличилась толщина других частей рамки.
Снова отключим маску и добавим дополнительную обводку для подложки.
Мы задали значения top и left равные -20px. Это увеличило размер подложки влево и вверх, из-за чего левая и верхняя части рамки стали толще, чем правая и нижняя.
Есть ли способ «обрезать» лишнюю толщину?
Если использовать background-color, обрезать часть фона, который имитирует рамку, не получится.
Вместо фонового цвета давайте используем фоновое изображение в виде одноцветного градиента. Зададим градиенту размер 100% 100%, то есть такой же, как размер блока, и запретим ему повторяться.
Внешне пока ничего не изменилось, так как фоновая картинка полностью заполняет блок.
Теперь сдвинем фоновое изображение с помощью background-position, например, на 10px вправо и 10px вниз.
Мы получили пустые области в левой и верхней части блока, потому что фоновое изображение сместилось. Правая и нижняя часть изображения вышли за границы блока.
Таким образом, с помощью фонового изображения мы «обрезали» лишние части рамки.
Уберём белую обводку и включим маску.
Теперь мы можем управлять толщиной наклонных частей рамки с помощью top и left, а обрезать лишнюю толщину прямых частей рамки — с помощью background-position.
Осталось методом научного тыка подобрать такие значения свойств, чтобы толщина всех частей рамки стала одинаковой.
Вот что получилось:
top: -18px;
left: -11px;
background-position: 1px 8px;
Если нужна другая толщина рамки (например, 4px), значения будут другие:
inset: -4px;
top: -6px;
left: -6px;
background-position: 1px 2px;
Теперь изменим цвета градиента у подложки. Вместо чёрного используем два оттенка синего: более светлый сверху и более тёмный снизу. Так рамка будет лучше сочетаться с фоном.
Вернём исходный цвет фона для карточки .card и снова сделаем её содержимое видимым.
Рамка, которая повторяет форму выреза, готова. Для её создания мы использовали подложку с абсолютным позиционированием, маску и градиент в качестве фонового изображения. Для управления толщиной разных частей рамки подбирали значения inset-свойств и позицию фонового изображения подложки.
Проведём небольшой рефакторинг селекторов и классов: перенесём модификатор с формой выреза на обёртку.
Теперь всё готово. Можно проверять этот подход на других вырезах.
Теперь подключим второй угловой вырез на коническом градиенте. Для этого добавим маску из второго выреза в абсолютную подложку. Посмотрим, что получилось.
Та же проблема с толщиной наклонных частей рамки.
Этот вырез симметричен по вертикали. Поэтому увеличим подложку только влево, используя left: -8px.
Зададим фон обложки с помощью градиента и обрежем его слева, используем background-position: 4px 0.
Во второй раз всё прошло проще.
Теперь подключим третий вырез — скос на линейном градиенте. Опять возникла проблема с толщиной наклонной части.
В этом случае проще настроить толщину рамки, изменив параметры градиента в маске подложки. Просто сместим позиции цвета в колорстопах.
Фон подложки можно заменить на линейный градиент, чтобы усилить визуальный эффект. Это улучшит сочетание рамки с фотографией на фоне.
И последний тип выреза — круглый вырез.
Здесь тоже возникает проблема с толщиной обводки. У нас есть две маски с одинаковыми радиусами. Одна маска смещена относительно другой влево. Поэтому и возникает эффект, который вы наблюдаете.
Это можно исправить, если изменить радиус одной из масок.
Поработаем с маской в подложке. Сначала выполним небольшой рефакторинг радиального градиента.
Превратим градиент в эллиптический с размерами 75px 75px. Для колорстопов зададим значения 99.5% и 100%.
Так удобнее менять радиусы градиента.
Попробуем немного «сплюснуть» маску подложки. Для этого уменьшим вертикальный радиус радиального градиента.
Выглядит хорошо.
Второй способ: сначала уменьшим оба радиуса градиента до 71px 71px. Иными словами, обе маски (в подложке и в карточке) представляют собой круги с разными радиусами. Радиус выреза в подложке меньше.
Затем сместим центр маски в подложке вправо с помощью at 3.5px 50%.
Тоже выглядит хорошо.
Закруглим углы самой карточки и зададим градиентный фон подложке. Карточка готова.
Подведём итог. Вырезы без рамок создаются легко. Рамки, которые повторяют форму выреза, создаются сложнее: потребуется абсолютное позиционирование подложки, работа с градиентным фоном, настройка координат подложки и позиции фона, а также навыки работы с CSS-градиентами.