Иногда кажется, что дизайнеры придумывают интерфейсные паттерны, чтобы поиздеваться над разработчиками. Впуклый угол — один из них.
«Инвертированный», «вогнутый», «впуклый» угол, а также negative border radius или inverted border radius. Когда слышите это — знайте, дальше будут страдания.
Проблема в том, что приём выглядит просто, но нативного способа сделать такой угол в CSS нет. Поэтому в ход идут тучи дополнительных обёрток и море стилей для их позиционирования. И всё это ломается на неоднородном фоне.
В этой статье я покажу простой способ создания впуклых углов с помощью опенсорсной CSS‑библиотеки, которую я разработал специально под эту задачу.
Почему инвертированные углы — это боль
Знакомьтесь с нашим героем на скриншоте:

Самый популярный способ реализации выглядит примерно так:
добавляем дополнительные обёртки и псевдоэлементы;
абсолютно позиционируем кусочки;
подгоняем радиусы, размеры и отступы.
На практике получаем море кода на каждый угол и хрупкое решение, которое сложно изменять.
Ниже скриншот одного из популярных роликов про реализацию впуклого угла. На скриншоте видна примерно одна пятая от общего объёма кода реализации.

Проблемы с фоном
Типовые решения работают только на сплошных фонах. Как только появляется неоднородный фон, нужно использовать SVG. И CSS‑боль превращается в SVG‑боль.
Решение мечты для впуклых углов
О чём мечтает разработчик, когда видит впуклый угол:
простое решение на чистом CSS;
работающее из коробки, в том числе на неоднородных фонах;
с возможностью нативной кастомизации размеров и формы углов.
И такое решение существует! Это библиотека nebo.css, с которой мы познакомимся в этой статье. Название происходит от названия паттерна — negative border radius.
Подключение nebo.css и первый впуклый угол
nebo.css — это один CSS‑файл, по духу очень похожий на normalize.css: подключил — и используешь. Внутри нет JavaScript, всё сделано на чистом CSS.
Подключаем библиотеку
<link rel="stylesheet" href="nebo.css">
Этого уже достаточно, чтобы начать.
Добавляем один угол карточке
Чтобы добавить инвертированный угол, элементу нужен базовый класс nebo. По умолчанию угол появляется снизу справа.
<article class="card nebo">...</article>
Результат:

Меняем сторону угла
Сторона задаётся мод��фикаторами:
nebo--tr— сверху справа,nebo--tl— сверху слева,nebo--bl— снизу слева,nebo--br— снизу справа.
<article class="card nebo nebo--tr">...</article>
Результат:

На этом этапе уже видно важную вещь: угол корректно работает даже на неоднородном фоне, без дополнительных ухищрений.
Базовая кастомизация
Все параметры nebo.css настраиваются через нативные CSS‑переменные, которые подчиняются обычному каскаду.
Общий радиус скруглений: --nb-r
Эта переменная управляет радиусами скруглений в угле. Значение по умолчанию — 20px. Немного уменьшим его.
.nebo { --nb-r: 16px; }
Ширина и высота выреза: --nb-w и --nb-h
Эти переменные задают дополнительные смещения между внутренним и внешними радиусами.
.card--cat1 { --nb-w: 42px; --nb-h: 16px; }
Результат:

Разные настройки для разных элементов
Так как мы работаем с обычным каскадом, каждый элемент можно настраивать по‑своему:
.card--cat1 { --nb-w: 42px; --nb-h: 16px; } .card--cat2 { --nb-w: 32px; --nb-h: 42px; } .card--cat3 { --nb-w: 64px; --nb-h: 42px; } .card--cat4 { --nb-w: 42px; --nb-h: 16px; }
Результат:

Кстати, углы корректно отображаются даже при нулевых значениях (0px) — главное не забывать единицы измерения.
Несколько инвертированных углов у одного элемента
nebo.css изначально решает одну задачу: один элемент — один угол. Но если нужно несколько углов, в ход идёт проверенный приём — дополнительная обёртка.
Используем обёртки
<div class="card-wrapper nebo nebo--bl"> <article class="card nebo nebo--tr">...</article> </div>
Результат:

Каждый уровень можно настраивать отдельно через CSS‑переменные. Можно собрать и три, и четыре угла — просто добавляя обёртки.
Продвинутая кастомизация
Общий радиус для всех скруглений, который задаётся с помощью переменной --nb-r, можно переопределить для каждого из трёх скруглений: двух внешних и одного внутреннего. Причём можно отдельно задать как вертикальные, так и горизонтальные радиусы. Это делается с помощью шести дополнительных CSS-переменных:
--nb-cor1-rw, --nb-cor1-rh, --nb-cor2-rw, --nb-cor2-rh, --nb-curve-rw, --nb-curve-rh,
Благодаря этим переменным можно получать впуклые углы очень сложных форм. Например:
.card--cat1 { --nb-r: 30px; --nb-w: 0px; --nb-h: 0px; --nb-curve-rw: 120px; --nb-curve-rh: 90px; --nb-cor1-rw: 90px; --nb-cor1-rh: 90px; --nb-cor2-rw: 60px; --nb-cor2-rh: 60px; --_nb-smooth: 99.5%; }
Результат:

Пример кейса: карточка из двух блоков
Теперь посмотрим на более жизненный кейс — карточку, состоящую из верхнего блока с изображением и нижнего блока с информацией.
Разметка
<div class="card"> <div class="card-header"></div> <div class="card-body"> <div class="price">$114,000</div> ... </div> </div>
Добавляем инвертированные углы
<div class="card-header nebo nebo--bl"></div> <div class="card-body nebo nebo--tr">...</div>
Настраиваем параметры и совмещаем блоки
В примере использован быстрый грязный приём с отрицательным маргином, чтобы подтянуть блок с картинкой к блоку с описанием. Но цель была — показать простоту создания вырезов.
.card-header { --nb-r: 10px; --nb-w: 130px; --nb-h: 44px; margin-bottom: -54px; } .card-body { --nb-r: 10px; --nb-w: 160px; --nb-h: 44px; }
Результат:

Обратите внимание, что всё отлично работает с неоднородным фоном.
Где взять nebo.css
nebo.css — это бесплатная опенсорсная библиотека, разработанная автором. Лежит на GitHub.
Репозиторий:
https://github.com/htmlacademy/nebo.css
Библиотеку можно просто подключить отдельным файлом или скопировать код прямо в свои стили. Пользуйтесь и наслаждайтесь!
А где взять ещё больше сложного CSS и код всех примеров?
Подписывайтесь на мой телеграм‑канал «CSS Боль». Там собраны все материалы, видеоролики, ссылки на интерактивные пошаговые демки