Иногда кажется, что дизайнеры придумывают интерфейсные паттерны, чтобы поиздеваться над разработчиками. Впуклый угол — один из них.

«Инвертированный», «вогнутый», «впуклый» угол, а также negative border radius или inverted border radius. Когда слышите это — знайте, дальше будут страдания.

Проблема в том, что приём выглядит просто, но нативного способа сделать такой угол в CSS нет. Поэтому в ход идут тучи дополнительных обёрток и море стилей для их позиционирования. И всё это ломается на неоднородном фоне.

В этой статье я покажу простой способ создания впуклых углов с помощью опенсорсной CSS‑библиотеки, которую я разработал специально под эту задачу.

Почему инвертированные углы — это боль

Знакомьтесь с нашим героем на скриншоте:

Видите форму как у красной линии — спасайтесь!
Видите форму как у красной линии — спасайтесь!

Самый популярный способ реализации выглядит примерно так:

  • добавляем дополнительные обёртки и псевдоэлементы;

  • абсолютно позиционируем кусочки;

  • подгоняем радиусы, размеры и отступы.

На практике получаем море кода на каждый угол и хрупкое решение, которое сложно изменять.

Ниже скриншот одного из популярных роликов про реализацию впуклого угла. На скриншоте видна примерно одна пятая от общего объёма кода реализации.

При��ер реализации от Kevin Powell
Пример реализации от Kevin Powell

Проблемы с фоном

Типовые решения работают только на сплошных фонах. Как только появляется неоднородный фон, нужно использовать 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 Боль». Там собраны все материалы, видеоролики, ссылки на интерактивные пошаговые демки