Пару лет назад в CSS произошла тихая революция, вызвавшая тектонический сдвиг в разработке интерфейсов. Вкратце — нам разрешили «сверлить» настоящие дырки в блоках.
Создание блоков с вырезами всегда было трудоёмким, даже для вырезов простейшей формы. Фронтендеры годами тренировались мысленно рассекать блоки на части: прямоугольничек для контента, прямоугольничек для выреза и ещё парочка рядом с ним. И вдруг парадигма поменялась...
Простые вырезы теперь делаются в десять раз быстрее. Одной строчкой кода. Да, надо менять мышление и забывать про нарезку блоков. И как же это приятно!
В статье мы сверстаем карточку с круглым вырезом двумя способами: традиционно‑дедовским и современным. Затем сравним объём кода, простоту и гибкость получившихся реализаций. И порадуемся, что будущее уже наступило!
Типовые требования к поведению компонента
Мы будем верстать эту карточку:

При реализации блоков с такими вырезами обычно учитывают два требования:
Под карточкой находится неоднородный фон: фотография или градиент, который должен по‑настоящему «просвечивать» в вырезе.
Карточка может изменять размеры. Если карточка резиновая, то она может изменять ширину, а при изменении контента может изменяться высота.
Парадигма приклеивания к блокам
У опытного верстальщика при взгляде на такой вырез возникают флэшбеки, а затем одна и та же схема:

Мы ищем прямоугольную область, в которой будет «жить» контент (выделена жёлтым). А затем «приклеиваем» к ней дополнительные элементы, которые формируют вырез.
Обычно вырез раскладывается на три части:
центральную — с фиксированными размерами (выделена зелёным);
верхнюю и нижнюю — которые растягиваются по высоте карточки (выделены красным).
Абсолютно типичный и рабочий подход. Давайте его реализуем.
Классическая реализация
Шаг 0. Базовая разметка
Начнём с самой простой разметки: одна карточка и контент внутри.
<div class="card"> <p class="tag">Устьянский район</p> <h1 class="headline">Осенние берега Устьи</h1> <p class="lead">Здесь природа говорит шёпотом —<br> ощути северную тишину.</p> <button class="button">Купить билет</button> </div>
Пока это просто набор текстовых элементов.

Шаг 1. Планируем "нарезку" компонента
Классическую реализацию мы сделаем с помощью флексбокса, чтобы она была понятна всем. Да, можно использовать и гриды, и позиционирование, но сути это не изменит. Поэтому используем флексбокс и планируем дополнительные обёртки с учётом этого.
Чтобы получить карточку с вырезом, нам понадобится две колонки. В одной колонке будет «жить» вырез, в другой — контент. Внутри колонки с вырезом будет три блока: верхний, центральный и нижний.
Центральный блок будет иметь фиксированную высоту, а крайние — растягиваться, подстраиваясь под высоту карточки.
Шаг 2. Добавляем обёртки в разметку
Добавим дополнительные обёртки.
<div class="card"> <div class="cutout"> <div class="cutout-top"></div> <div class="cutout-center"></div> <div class="cutout-bottom"></div> </div> <div class="card-content"> <p class="tag">Устьянский район</p> <h1 class="headline">Осенние берега Устьи</h1> <p class="lead">Здесь природа говорит шёпотом —<br> ощути северную тишину.</p> <button class="button">Купить билет</button> </div> </div>
Уже сейчас видно, как DOM начал разрастаться.
Шаг 3. Базовая геометрия карточки
Делаем карточку флекс‑контейнером и задаём ширины колонок. Нам приходится подбирать ширину блоков и внутренние отступы, чтобы получить нужное расстояние от контента до выреза.
.card { display: flex; width: 620px; } .card-content { width: 420px; padding: 50px; padding-left: 75px; color: #6b5742; background-color: #fdf6f0; } .cutout { width: 75px; }
Теперь у нас есть две колонки: контент и будущий вырез.

Шаг 4. Стилизуем блоки вокруг выреза
Превращаем блок .cutout во флекс‑контейнер и направляем его главную ось вниз. Верхний и нижний блоки растягиваем по высоте с помощью flex-grow: 1; и задаём им фон. Центральному блоку, внутри которого будет изображение для выреза, задаём фиксированную высоту.
.cutout { display: flex; flex-direction: column; } .cutout-top, .cutout-bottom { flex-grow: 1; background-color: #fdf6f0; } .cutout-center { height: 150px; }
При изменении высоты карточки крайние элементы растягиваются, центральный остаётся фиксированным.

Шаг 5. Рисуем сам вырез
Форму выреза можно реализовать по‑разному: использовать PNG с полупрозрачностью, или SVG, или нарисовать с помощью CSS‑градиента. Мы используем радиальный градиент, чтобы не подключать лишнюю картинку.
.cutout-center { height: 150px; background-image: radial-gradient( circle at 0 50%, transparent 74.5px, #fdf6f0 75px ); }
Вырез появился. Карточка выглядит как задумано.

Проверяем на переполнение
Добавим больше текста. Высота карточки увеличилась — вырез остался на месте. Всё работает.

Реализация готова. Можно подвести итог. Нам понадобилось 5 дополнительных обёрток и около 20 строчек кода. Это не смертельно. Карточка ведёт себя хорошо. За исключением одного неприятного ограничения.
Ограничение — неоднородный фон у карточки
Попробуем добавить карточке градиентный фон. Добавляем его блоку с контентом.
.card-content { background-image: linear-gradient(135deg, #fff6e9, #fdd9b5, #f4a261); }
Нам нужно, чтобы фон заполнял всю карточку, поэтому добавим его и блокам .cutout-top и .cutout-bottom:
.cutout-top, .cutout-bottom { background-image: linear-gradient(135deg, #fff6e9, #fdd9b5, #f4a261); }
И тут становится больно. Карточка состоит из отдельных блоков и фон ломается на стыках.

Состыковать фон разных частей принципиально невозможно, так как размеры карточки могут меняться.
Выводы по классическому подходу
Классический способ работает, но:
требует дополнительных обёрток;
заставляет писать много CSS;
не позволяет задавать неоднородный фон самой карточке.
А теперь давайте посмотрим, как ту же задачу можно решить иначе.
Современная реализация
Ключевая идея проста: вместо того чтобы склеивать карточку из отдельных кусочков, мы делаем вырез в нужном месте карточки.

Для этого нам понадобятся CSS‑маски.
Шаг 1. Возвращаемся к простой карточке
Убираем все дополнительные обёртки и оставляем один элемент .card. Единственное изменение — размер отступа слева. Увеличиваем его с учётом размера выреза.
.card { width: 420px; padding: 50px; padding-left: 150px; color: #6b5742; background-color: #fdf6f0; }
Результат такой:

Шаг 2. Добавляем одно свойство — mask-image
.card { mask-image: radial-gradient( circle at 0 50%, transparent 74.5px, black 75px ); }
Всё. Карточка с вырезом готова.

Лирическое отступление: как работает эта маска
Не так много разработчиков знакомы с CSS‑масками, да и радиальные градиенты никогда не отличались популярностью. Поэтому давайте подробнее разберём, как сделан этот вырез.
Семейство свойств mask-* работает почти так же как семейство свойств background-*. Если вы работали с фоновыми изображениями, то и с масками разберётесь быстро.
Чтобы понять механику, заменим mask-image на background-image. Это позволит увидеть форму маски. Вначале создадим простейший радиальный градиент, круглой формы с двумя цветами (прозрачным и чёрным):
background-image: radial-gradient( circle, transparent, black );
Результат:

Теперь добавим резкий цветовой переход между цветами, задав очень близкие позиции цвета в колорстопах. Разница в полпикселя нужна, чтобы сгладить края перехода и убрать эффект зубцов.
background-image: radial-gradient( circle, transparent 74.5px, black 75px );
Результат:

Сместим центр градиента на середину левой стороны блока с помощью at 0 50%. Форма маски готова.
background-image: radial-gradient( circle at 0 50%, transparent 74.5px, black 75px );
Результат:

Прозрачная часть — это то, что будет вырезано. Чёрная — то, что останется. Чтобы получить вырез, остаётся только заменить background-image на mask-image.
Переполнение и неоднородный фон
Благодаря использованию маски карточка остаётся цельной. Поэтому:
она корректно реагирует на изменение высоты и ширины;
карточке можно задавать неоднородный фон (градиент, изображение);
можно комбинировать несколько фонов.
.card { background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1) 50%, transparent 51%), linear-gradient(135deg, #fff6e9, #fdd9b5, #f4a261); background-repeat: repeat-y, no-repeat; background-size: 1.5px 20px, auto auto; background-position: 115px 4px, 0 0; }
В результате мы получили карточку с неоднородным фоном и «линией отреза»:

Выводы по современной реализации
Реализация выреза на CSS‑масках на порядок лучше старого подхода:
дополнительные обёртки не нужны;
используется всего одно CSS‑свойство;
позволяет задавать неоднородный фон самой карточке.
Поддержка CSS-масок — всё отлично!
Маски доступны во всех современных браузерах уже несколько лет, а радиальные градиенты — и того дольше.
Смена парадигмы
Старая парадигма «приклеивания к блокам», в которой мы собирали вырезы из нескольких частей, умирает. На замену ей приходит парадигма «вырезания из блоков», которая на порядок упрощает создание вырезов и даёт дополнительную гибкость при использовании фонов.
Будущее уже здесь!
А где взять ещё больше сложного CSS и код всех примеров?
Подписывайтесь на мой телеграм‑канал «CSS Боль». Там собраны все материалы, видеоролики, ссылки на интерактивные пошаговые демки
Комментарии (24)

codaink
06.02.2026 10:07Огонь, даже не подозревал что так можно. А что с поддержкой браузеров, в статье не уточнили?

AlexPershin Автор
06.02.2026 10:07отличная поддержка, в статье отдельный заголовок под это отведён. widely avaliable уже через пару месяцев будет

aamonster
06.02.2026 10:07Только чтобы нормально пользоваться – надо не "Wildely available", а чтобы "даже у последнего владельца нокии 3310" правильно отображалось.
Т.е. придётся всю кухню со сложным методом всё равно делать и включать для легаси браузеров. Ну или просто отключить на них вырез (в душе не понимаю, правда, почему не сделать то же самое для всех платформ: мне, как посетителю сайта, он нафиг не нужен).

AlexPershin Автор
06.02.2026 10:07Ну не у всех же сервисы на миллионы юзеров. Для огромного количества сегментов вайдли авайлаболь и даже ньюли авайлаболь уже достаточно

aamonster
06.02.2026 10:07Они могут не выпендриваться и просто обходиться без технически сложных элементов дизайна, если не готовы поддерживать легаси.

AlexPershin Автор
06.02.2026 10:07В случае с вырезами пользователи старых браузеров отлично обойдутся и без них

VVitaly
06.02.2026 10:07:-) Да уж.... Вот такие "вырезы" современный веб и "тормозят"....

AlexPershin Автор
06.02.2026 10:07Это камень в огород дизайнеров или тех, кому приходится их задумки реализовывать? =)

PaulZi
06.02.2026 10:07Такие вырезы лучше делать через clip-path, а не через маски с градиентами. Уверен, это на порядки производительнее чем маски с градиентами.

AlexPershin Автор
06.02.2026 10:07А можете прислать пример реализации такого же выреза на clip-path?
И если под рукой завалялась спека или какая-то другая техническая статья про производительность двух методов, буду благодарен, хочу покопать этот вопрос

PaulZi
06.02.2026 10:07https://codesandbox.io/p/sandbox/s6wlgy
Вот накидал варианты c clip-path с svg (потому что просто через path не масштабируется) и вариант через shape (с последним пока нет поддержки в firefox). Кривоватенько, но суть понятна.
По производительности тесты не проводил, думаю это будет хорошей основой для новой статьи.

AlexPershin Автор
06.02.2026 10:07Спасибо, поигрался с вашими вариантами. Честно говоря, убедился что для таких простых задач маски намного лучше, чем
clip-pathС точки зрения поддержки вариант с SVG сопоставим с масками. Но он требует тащить в проект отдельное свг-изображение. Само это изображение надо предварительно где-то отрисовать. И вот вопрос — а зачем мне тащить в реализацию свг, если я справляюсь одним свойством без SVG
Вариант на shape плохо поддерживается, синтаксис намного сложнее, да и форма выреза получилась не круглой, а какой-то овальной.
Единственный аргумент за усложнение своей жизни с
clip-path— это производительность. Но у меня огромные сомнения, что маски по производительности отличаются от клип-пасов. Может быть есть ссылки на статьи, где этот вопрос разбирается? Я где-то слышал (но сам не проверял), что маски рендерятся на GPU, и если это так, то с производительностью там должно быть всё отлично.

Metotron0
06.02.2026 10:07В перчую очередь пришла на ум маска, но я знал, что она работает с картинками, про градиенты не задумывался. Подумал было, что речь пойдёт про какое-то новое свойство, типа corder-shape. Но тоже пригодится. Хорошо, что мне обычно таких вещей верстать не приходится.
К слову, в варианте с тремя блоками я бы сделал не дивы сверху и снизу, а after и before.
howk
Вот бы еще был способ делать такие сложные закругления при которых корректно отрабатывали внешние и внутренние тени для блоков
AlexPershin Автор
Внешние тени решаются обёрткой со свойством
filter: drop-shadow(...)Не помню только, поддерживает ли этот фильтр внутренние тениgoncharovyelisey
В том то и дело, что это свойство работает с реальным контуром элемента, и сложные зкаругления, вроде того, что есть в статье он будет бесполезен. В таких случаях обычно приходится играться с псевдоэлементами и масками, ну либо использовать магией svg, что бы совсем уж без заморочек
AlexPershin Автор
Посмотрите на скриншот ниже. С внешней тенью отлично справляется. С внутренней — нет.
Но смысл статьи не в этом. Раньше для простых вырезов нужно было делать сложную реализацию, и для сложных вырезов тоже нужно было делать сложную реализацию.
А сейчас для простых вырезов у нас есть простейшее решение в одну строчку. А для сложных вырезов остаются сложные решения, никуда не деться. Но как минимум появляется возможность искать компромисс с дизайнером "упрощаем дизайн и делаем блок за 5 минут" или "оставляем сложный дизайн и убиваем на реализацию день"
AlexPershin Автор
вот быстрый пример. специально сделал красную тень