12k
All articles

Как убрать лишнее пространство над текстом и под ним в CSS

Уберите лишнее пространство над и под текстом с помощью text-box-trim в CSS. Разберитесь с метриками шрифта и line-height, выберите text-box-edge и настройте поддержку старых браузеров.

OpenReplay Team
OpenReplay Team
Как убрать лишнее пространство над текстом и под ним в CSS

Лишнее пространство над текстом и под ним возникает из двух источников: собственных вертикальных метрик шрифта и полуинтерлиньяжа (half-leading), который line-height добавляет (или отнимает) с каждой стороны строки. Нативное решение в CSS — text-box: trim-both cap alphabetic.

Вы задали line-height: 1.1, убрали все отступы, а заголовок всё равно находится в блоке, который выше самих букв. Тогда вы добавили отрицательный margin, подбирали его, пока не стало выглядеть нормально, и забыли об этом. А потом сменился фирменный шрифт.

В этой статье разберём, откуда берётся это пространство, почему отрицательные отступы не позволяют надёжно от него избавиться и как с помощью text-box-trim, text-box-edge и сокращённого свойства text-box обрезать его у заголовков и кнопок. В конце приведён вариант резервного решения для старых браузеров.

Ключевые выводы

  • Лишнее пространство вокруг текста складывается из вертикального места, которое шрифт резервирует под самые высокие и самые глубокие глифы, и интерлиньяжа, который добавляет или отнимает line-height. CSS делит его поровну над и под каждой строкой.
  • text-box-trim определяет, какие края обрезать (none, trim-start, trim-end, trim-both), а text-box-edge — до какой линии обрезается каждый край.
  • text-box: trim-both cap alphabetic обрезает верх до высоты прописных букв, а низ — до базовой линии, что соответствует тому, как в большинстве макетов измеряются отступы.
  • text-box-edge ни на что не влияет, если для text-box-trim не задано значение, отличное от none.
  • text-box-trim не наследуется, поэтому объявляйте его для каждого элемента, который нужно обрезать, а не для body.

Симптом: зазор, который не объясняется внутренними отступами

У заголовка с нулевыми padding и margin и плотным line-height всё равно остаётся пустое пространство над прописными буквами и под базовой линией. DevTools показывает, что область содержимого (content box) выше видимых букв, и ничто в ваших стилях этой разницы не объясняет.

Обычная «заплатка» — отрицательный margin, подобранный методом проб и ошибок:

h1 {
  line-height: 1.1;
  /* Tuned by eye for one font; wrong for any other */
  margin-block: -0.2em -0.15em;
}

Эти значения приведены лишь для иллюстрации. Они ни из чего не выводятся — в этом-то и проблема.

Откуда берётся лишнее пространство над текстом и под ним?

У лишнего пространства над текстом и под ним две причины — метрики шрифта и полуинтерлиньяж, и обе относятся к самому тексту, а не к блочной модели.

Во-первых, шрифт отводит вертикальное пространство под все свои глифы — от высоких прописных букв до хвостиков таких букв, как g и y. Объём этого пространства различается от гарнитуры к гарнитуре, как отмечается в справочнике MDN по text-box-trim, поэтому при одном и том же font-size строчный бокс (line box) получается выше или ниже в зависимости от шрифта.

Во-вторых, line-height добавляет интерлиньяж. Спецификация CSS 2.1 об интерлиньяже и полуинтерлиньяже определяет интерлиньяж как разницу между line-height и суммой верхнего и нижнего выносов шрифта (ascent и descent). Половина этой величины добавляется над глифами, половина — под ними. У многих шрифтов сумма ascent и descent превышает 1.1em, поэтому при line-height: 1.1 полуинтерлиньяж часто оказывается небольшим или даже отрицательным. В любом случае пустое пространство, которое оставляют собственные метрики шрифта над прописными буквами и под базовой линией, никуда не девается.

Каждая гарнитура резервирует разный объём вертикального пространства, поэтому отрицательный отступ, подобранный под один шрифт, не подходит для другого. Это касается и резервного шрифта, который отображается до загрузки веб-шрифта, — та же проблема вызывает и сдвиги макета, связанные со шрифтами. Если воспроизвести запись сессии, в которой веб-шрифт загружается с опозданием, можно увидеть кадр, где шрифт подменяется и заголовок с «магическим» отступом прыгает.

Как убрать зазор с помощью text-box-trim?

text-box-trim определяет, какие края текстового блока обрезаются, а text-box-edge — до какой линии обрезается каждый край. text-box-trim принимает четыре ключевых слова:

  • none: начальное значение. Ничего не обрезается.
  • trim-start: обрезает верхний (over) край.
  • trim-end: обрезает нижний (under) край.
  • trim-both: обрезает оба края.

Вот тот же заголовок, где хак с отступом заменён:

h1 {
  line-height: 1.1;
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}

После применения text-box-trim верхний край блока совпадает с верхом прописных букв, а нижний — с базовой линией. Лишнее пространство исчезает для любого шрифта, потому что браузер берёт нужные позиции из самого шрифта, а не из ваших догадок.

Сокращённое свойство text-box объединяет оба свойства в одном объявлении. Эти два правила эквивалентны:

h1 {
  text-box: trim-both cap alphabetic;
}

/* Same result: an omitted trim keyword means trim-both */
h1 {
  text-box: cap alphabetic;
}

Какие значения text-box-edge важны?

Для горизонтального текста почти все случаи покрывают две пары значений: cap alphabetic и ex alphabetic. text-box-edge принимает два ключевых слова: первое задаёт верхний край, второе — нижний.

Ключевое словоКрайДо чего обрезает
textверхний или нижнийдо текстового края шрифта (именно в это значение разрешается auto по умолчанию)
capтолько верхнийдо верха прописных букв
exтолько верхнийдо высоты строчных (x-height, верх коротких строчных букв)
alphabeticтолько нижнийдо алфавитной базовой линии

cap alphabetic соответствует тому, как дизайнеры обычно измеряют пространство вокруг заголовка или подписи: от высоты прописных до базовой линии. Используйте ex alphabetic, если текст набран в основном строчными буквами и визуальным верхом служит x-height:

.lowercase-label {
  text-box: trim-both ex alphabetic;
}

На трёх правилах спотыкается большинство:

  • text-box-edge само по себе ни на что не влияет. Ничего не обрезается, пока для text-box-trim не задано значение, отличное от none.
  • В сокращённом свойстве text-box пропущенное ключевое слово обрезки означает trim-both, а пропущенный край — auto. Ключевое слово normal эквивалентно none auto.
  • Ни text-box-trim, ни text-box-edge не наследуются. Если задать их для body, заголовки и кнопки внутри него обрезаны не будут. Объявляйте свойства для каждого элемента или в базовых стилях каждого компонента.

Центрирование подписи на кнопке с помощью text-box

На кнопке с одинаковыми внутренними отступами сверху и снизу подпись часто выглядит смещённой. Отступы равны, а вот внутреннее пространство шрифта над прописными буквами и под базовой линией — нет, и эта разница воспринимается как дополнительный отступ с одной стороны.

.button {
  padding: 0.75rem 1.25rem;
}

Если обрезать блок подписи до высоты прописных и базовой линии, единственным пространством между текстом и краем кнопки останется padding:

.button--trimmed {
  padding: 0.75rem 1.25rem;
  text-box: trim-both cap alphabetic;
}

С подписью вроде «Submit» пространство над прописными буквами теперь выглядит так же, как пространство под базовой линией. Спецификация CSS Inline Layout допускает применение text-box-trim к блочным контейнерам, многоколоночным контейнерам и строчным боксам, однако браузеры ведут себя по-разному. Согласно намерению Mozilla выпустить функцию (intent to ship), Firefox и Safari обрезают строчные боксы, а Chromium — нет. Кроме того, обрезка не действует на flex- и grid-контейнеры, поэтому задайте кнопке display: inline-block или примените обрезку к элементу подписи внутри неё. Поскольку нижний край обрезается до базовой линии, нижние выносные элементы букв g, p и y заходят в область padding. Это ожидаемый с точки зрения типографики результат, а не ошибка.

Поддержка браузерами и резервное решение

MDN относит text-box к Baseline 2026 (newly available с августа 2026 года) и отмечает, что свойство может не работать на старых устройствах и в старых браузерах. Браузеры без поддержки игнорируют объявление и отображают текст с обычными шрифтовыми интервалами. Резервный вариант — макет без обрезки: он не сломан, просто менее точен. Если дизайн зависит от прежних компенсирующих отступов, оставьте их только для таких браузеров с помощью запроса поддержки функций @supports:

h1 {
  text-box: trim-both cap alphabetic;
}

@supports not (text-box: trim-both cap alphabetic) {
  h1 {
    /* Old per-font patch, kept only where text-box is unsupported */
    margin-block: -0.2em -0.15em;
  }
}

Заключение

Зазор вокруг текста — это метрики шрифта плюс полуинтерлиньяж. Отрицательный отступ лишь маскирует его, да и то только для одной гарнитуры. Замените такие отступы на text-box: trim-both cap alphabetic в каждом компоненте заголовка и подписи, перенесите устаревшие отступы в блок @supports not и проверьте результат как с веб-шрифтом, так и с резервным шрифтом.

Часто задаваемые вопросы

Меняет ли text-box-trim расстояние между строками в многострочном абзаце?

Нет. В блочном контейнере text-box-trim затрагивает только верх первой строки и низ последней. Полуинтерлиньяж между переносимыми строками остаётся прежним, поэтому line-height по-прежнему управляет интервалами внутри абзаца. Смещаются только внешние края блока — до высоты прописных и базовой линии.

Почему бы просто не задать line-height: 1, чтобы убрать лишнее пространство?

line-height: 1 меняет только интерлиньяж. Собственное пространство шрифта над прописными буквами и под базовой линией остаётся, поэтому края блока всё равно не совпадают с высотой прописных и базовой линией. К тому же это уплотняет расстояние между переносимыми строками. text-box-trim обрезает по метрикам шрифта только внешние края, оставляя line-height свободным для управления удобочитаемостью.

Влияет ли обрезка с помощью text-box на расположение соседних элементов?

Да. text-box-trim смещает края содержимого элемента до выбранных метрик, поэтому элемент занимает меньше места по блочной оси. Отступы, промежутки (gap) во flex и grid, а также соседние элементы отсчитываются от обрезанного края, а не от зарезервированного шрифтом пространства. Именно поэтому после обрезки токены отступов визуально соответствуют макету — и поэтому важно убрать старые отрицательные отступы.

Как определить поддержку text-box в JavaScript?

Вызовите CSS.supports('text-box', 'trim-both cap alphabetic'). Метод возвращает true в браузерах, которые принимают это объявление, и false в остальных. Он выполняет ту же проверку, что и правило @supports в CSS, поэтому с его помощью можно во время выполнения решать, применять ли компенсирующие отступы, или логировать, какой вариант отрисовки получает пользователь.

Open-source session replay

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.